웹 요청 당 하나의 DbContext… 왜?


398

DbContext다양한 DI 프레임 워크를 사용하여 HTTP 웹 요청마다 하나만 작성하고 사용하도록 Entity Framework를 설정하는 방법을 설명하는 많은 기사를 읽었습니다 .

왜 이것이 처음부터 좋은 생각입니까? 이 방법을 사용하면 어떤 이점이 있습니까? 이것이 좋은 아이디어가되는 특정한 상황이 있습니까? 이 방법을 사용하여 DbContext저장소 메소드 호출 당 인스턴스를 작성할 때 수행 할 수없는 작업이 있습니까?


9
mehdi.me/ambient-dbcontext-in-ef6의 Gueddari 는 리포지토리 메서드 당 반 패턴을 호출하여 DbContext 인스턴스를 호출합니다. 인용 : "이 작업을 수행하면 Entity Framework가 DbContext를 통해 제공하는 1 차 수준 캐시, ID 맵, 작업 단위, 변경 내용 추적 및 지연 로딩 기능 등 거의 모든 기능을 잃어 버리게됩니다 " DBContext의 수명주기를 처리하기위한 훌륭한 제안이 포함 된 훌륭한 기사. 확실히 읽을만한 가치가 있습니다.
Christoph

답변:


564

참고 :이 답변은 Entity Framework에 대해 이야기 DbContext하지만 LINQ to SQL DataContext및 NHibernate 와 같은 모든 종류의 작업 단위 구현에 적용됩니다 ISession.

Ian을 반향하여 시작하겠습니다 DbContext. 전체 응용 프로그램에 대해 하나 를 갖는 것은 나쁜 생각입니다. 이것이 적합한 유일한 상황은 단일 스레드 응용 프로그램과 해당 단일 응용 프로그램 인스턴스에서만 사용되는 데이터베이스가있는 경우입니다. 는 DbContext스레드 안전하지하고 있기 때문에 DbContext데이터를 캐시, 그것은 오래된 곧 가져옵니다. 이렇게하면 여러 사용자 / 응용 프로그램이 해당 데이터베이스에서 동시에 작업 할 때 모든 종류의 문제가 발생합니다 (물론 매우 일반적입니다). 그러나 나는 당신이 이미 그것을 알고 있고 그것을 필요로하는 사람에게 새로운 인스턴스 (즉, 일시적인 생활 방식)를 주입하지 않는 이유를 알고 싶어 DbContext합니다. (단일 DbContext스레드 당 또는 컨텍스트 당 컨텍스트가 나쁜 이유에 대한 자세한 내용은 이 답변을 읽으십시오 ).

DbContext일시적 으로 as 를 등록하면 효과가 있지만 일반적으로 특정 범위 내에서 이러한 작업 단위의 단일 인스턴스를 가지기를 원합니다. 웹 응용 프로그램에서는 웹 요청의 경계에 이러한 범위를 정의하는 것이 실용적입니다. 따라서 웹당 요청 라이프 스타일입니다. 이를 통해 전체 개체 집합이 동일한 컨텍스트 내에서 작동 할 수 있습니다. 즉, 동일한 비즈니스 트랜잭션 내에서 작동합니다.

동일한 컨텍스트 내에서 일련의 작업을 수행하려는 목표가 없으면 일시적인 라이프 스타일은 좋지만 몇 가지주의해야 할 사항이 있습니다.

  • 모든 객체는 자체 인스턴스를 가져 오므로 시스템 상태를 변경하는 모든 클래스는 호출해야합니다 _context.SaveChanges()(그렇지 않으면 변경 사항이 손실 됨). 이는 코드를 복잡하게 만들고 코드에 두 번째 책임 (컨텍스트 제어 책임)을 추가하며 단일 책임 원칙을 위반하는 것입니다 .
  • DbContext다른 클래스의 컨텍스트 인스턴스에서 사용할 수 없으므로 [로드하여 저장 한 ] 엔터티가 해당 클래스의 범위를 벗어나지 않도록해야합니다. 엔티티가 필요할 때 ID로 다시로드해야하므로 성능 문제가 발생할 수 있기 때문에 코드가 엄청나게 복잡해질 수 있습니다.
  • DbContext구현 하기 때문에 IDisposable여전히 생성 된 모든 인스턴스를 삭제하려고합니다. 이렇게하려면 기본적으로 두 가지 옵션이 있습니다. 을 호출 한 직후에 동일한 방법으로 처리해야 context.SaveChanges()하지만,이 경우 비즈니스 로직은 외부에서 전달 된 객체의 소유권을 가져옵니다. 두 번째 옵션은 생성 된 모든 인스턴스를 Http 요청의 경계에 배치하는 것입니다. 그러나이 경우 해당 인스턴스를 폐기해야 할시기를 컨테이너에 알리려면 범위를 지정해야합니다.

다른 옵션은 전혀 주입 하지 않는DbContext 것입니다. 대신 DbContextFactory새 인스턴스를 만들 수 있는 a를 삽입 합니다 (이전에이 방법을 사용 했었습니다). 이렇게하면 비즈니스 로직이 컨텍스트를 명시 적으로 제어합니다. 다음과 같이 보일 수 있습니다 :

public void SomeOperation()
{
    using (var context = this.contextFactory.CreateNew())
    {
        var entities = this.otherDependency.Operate(
            context, "some value");

        context.Entities.InsertOnSubmit(entities);

        context.SaveChanges();
    }
}

이것의 장점은 DbContext명시 적으로 수명을 관리하고 쉽게 설정할 수 있다는 것입니다. 또한 특정 범위에서 단일 컨텍스트를 사용할 수 있으므로 단일 비즈니스 트랜잭션에서 코드를 실행하고 엔티티가 동일한 위치에서 시작하므로 엔티티를 전달할 수있는 것과 같은 분명한 이점이 DbContext있습니다.

단점은 DbContext메쏘드에서 메쏘드 (메서드 인젝션이라고 함) 를 전달해야한다는 것입니다 . 어떤 의미에서이 솔루션은 '범위'접근 방식과 동일하지만 이제 범위는 응용 프로그램 코드 자체에서 제어되며 여러 번 반복 될 수 있습니다. 작업 단위 작성 및 처리를 담당하는 응용 프로그램입니다. DbContext의존성 그래프가 생성 된 후에 생성 되기 때문에 생성자 주입은 그림에서 벗어나므로 한 클래스에서 다른 클래스로 컨텍스트를 전달해야하는 경우 메소드 삽입을 연기해야합니다.

Method Injection은 그렇게 나쁘지는 않지만 비즈니스 로직이 더 복잡해지고 더 많은 클래스가 참여할 때 메소드에서 메소드로, 클래스로 클래스를 전달해야합니다. 이것은 과거에). 간단한 응용 프로그램의 경우이 접근법은 잘 작동합니다.

단점으로 인해이 팩토리 접근 방식은 더 큰 시스템에 적용되며 다른 접근 방식이 유용 할 수 있으며 이는 컨테이너 또는 인프라 코드 / 컴포지션 루트 가 작업 단위를 관리하게하는 접근 방식입니다. 이것이 당신의 질문에 관한 스타일입니다.

컨테이너 및 / 또는 인프라에서이를 처리 할 수있게함으로써 UoW 인스턴스를 생성 (선택 사항) 커밋 및 처리하여 비즈니스 로직을 단순하고 깨끗하게 유지함으로써 애플리케이션 코드가 오염되지 않습니다 (단일 책임). 이 방법에는 몇 가지 어려움이 있습니다. 예를 들어, 인스턴스를 커밋하고 처리 했습니까?

작업 단위 처리는 웹 요청이 끝날 때 수행 할 수 있습니다. 그러나 많은 사람들 이 이것이 작업 단위를 커밋하는 장소라고 잘못 생각합니다. 그러나 애플리케이션의 시점에서 작업 단위가 실제로 커밋되어야하는지 확인할 수 없습니다. 예를 들어 비즈니스 계층 코드가 콜 스택에서 더 높은 예외를 발생시킨 경우 커밋 하지 않을 것 입니다.

실제 솔루션은 다시 일종의 범위를 명시 적으로 관리하는 것이지만 이번에는 컴포지션 루트 내에서 수행합니다. 명령 / 핸들러 패턴 뒤에있는 모든 비즈니스 로직을 추상화 하면이를 수행 할 수있는 각 명령 핸들러를 감싸는 데코레이터를 작성할 수 있습니다. 예:

class TransactionalCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    readonly DbContext context;
    readonly ICommandHandler<TCommand> decorated;

    public TransactionCommandHandlerDecorator(
        DbContext context,
        ICommandHandler<TCommand> decorated)
    {
        this.context = context;
        this.decorated = decorated;
    }

    public void Handle(TCommand command)
    {
        this.decorated.Handle(command);

        context.SaveChanges();
    } 
}

따라서이 인프라 코드를 한 번만 작성하면됩니다. 모든 견고한 DI 컨테이너를 사용하면 그러한 데코레이터가 모든 ICommandHandler<T>구현을 일관된 방식으로 감싸도록 구성 할 수 있습니다 .


2
와우-철저한 답변에 감사드립니다. 내가 두 번 투표 할 수 있다면 위에서 "... 모든 작업 세트가 동일한 컨텍스트 내에서 작동하게 할 의도는 없습니다.이 경우 일시적인 라이프 스타일은 양호합니다 ..."라고 말합니다. 특히 "일시적"이란 무엇입니까?
Andrew

14
@Andrew : 'Transient'는 의존성 주입 개념으로, 서비스가 일시적으로 구성되면 서비스에 소비자에게 주입 될 때마다 서비스의 새 인스턴스가 작성됨을 의미합니다.
Steven

1
@ user981375 : CRUD 작업의 경우 일반 CreateCommand<TEnity>및 일반을 생성 할 수 있습니다 CreateCommandHandler<TEntity> : ICommandHandler<CreateCommand<TEntity>>(업데이트 및 삭제에 대해 동일하게 수행하고 단일 GetByIdQuery<TEntity>쿼리 를 가짐 ). 여전히이 모델이 CRUD 작업에 유용한 추상화인지 아니면 복잡성을 추가하는지 여부를 스스로에게 문의해야합니다. 그러나이 모델을 사용하여 (데코레이터를 통해) 교차 절단 문제를 쉽게 추가 할 수 있다는 이점이 있습니다. 장단점을 측정해야합니다.
Steven

3
+1 실제로이 글을 읽기 전에이 답을 모두 썼다고 생각 하십니까? 당신이 마지막에 DbContext의 폐기를 논의하기 위해 BTW IMO 나는 그것의 중요한 생각 (가장 큰하지만 당신있는 거 체류 컨테이너 무관)
루벤 Bartelink

1
그러나 장식 된 클래스에 컨텍스트를 전달하지 않습니다. 장식 된 클래스가 TransactionCommandHandlerDecorator? 예를 들어 데코 레이팅 된 클래스가 InsertCommandHandler클래스 인 경우 컨텍스트에 삽입 작업을 어떻게 등록 할 수 있습니까 (EF의 DbContext)?
Masoud

34

여기에 단일 답변이 실제로 질문에 대한 답변이 아닙니다. OP는 싱글 톤 / 애플리케이션 당 DbContext 디자인에 대해 묻지 않았으며, 웹별 요청 디자인과 존재할 수있는 잠재적 이점에 대해 질문했습니다.

Mehdi는 환상적인 리소스이므로 http://mehdi.me/ambient-dbcontext-in-ef6/ 를 참조하겠습니다 .

가능한 성능 향상.

각 DbContext 인스턴스는 데이터베이스에서로드하는 모든 엔티티의 첫 번째 레벨 캐시를 유지 보수합니다. 기본 키로 엔터티를 쿼리 할 때마다 DbContext는 기본적으로 데이터베이스에서 쿼리하도록 기본 설정하기 전에 첫 번째 수준 캐시에서 엔터티를 검색하려고 시도합니다. 데이터 쿼리 패턴에 따라 여러 순차 비즈니스 트랜잭션에서 동일한 DbContext를 재사용하면 DbContext 1 차 레벨 캐시로 인해 데이터베이스 쿼리가 줄어 듭니다.

지연 로딩이 가능합니다.

뷰 모델이나 다른 종류의 DTO를 반환하는 것과 달리 서비스가 영구 엔터티를 반환하고 해당 엔터티에 지연로드를 활용하려는 경우 해당 엔터티가 검색된 DbContext 인스턴스의 수명이 연장되어야합니다. 비즈니스 거래의 범위. 서비스 메소드가 리턴하기 전에 사용했던 DbContext 인스턴스를 처리 한 경우 리턴 된 엔티티에서 특성을 지연로드하려는 시도는 실패합니다 (지연로드를 사용하는지 여부에 관계없이 우리가 다루지 않을 다른 논쟁은 좋은 아이디어입니다) 여기). 웹 애플리케이션 예제에서 lazy-loading은 일반적으로 별도의 서비스 계층에서 반환 된 엔터티의 컨트롤러 작업 메서드에 사용됩니다. 이 경우

단점도 있습니다. 이 링크에는 주제를 읽을 수있는 다른 많은 자료가 들어 있습니다.

다른 사람 이이 질문에 걸려 넘어 실제로 질문을 해결하지 못하는 답변에 열중하지 않는 경우에 대비하여 게시하십시오.


좋은 링크! DBContext를 명시 적으로 관리하는 것이 가장 안전한 방법처럼 보입니다.
aggsol

34

Microsoft의 두 가지 상충되는 권장 사항이 있으며 많은 사람들이 DbContexts를 완전히 다른 방식으로 사용합니다.

  1. DbContext Alive가 DB 연결 등과 같은 귀중한 리소스를 차지하기 때문에 가능한 한 빨리 DbContext 를 처리하는 것이 좋습니다 .
  2. 다른 하나는 요청 당 하나의 DbContext가 권장된다고 말합니다.

귀하의 요청이 Db와 관련이없는 많은 일을하는 경우 DbContext는 아무런 이유없이 유지되기 때문에 서로 모순됩니다. 따라서 귀하의 요청이 임의의 작업이 완료되기를 기다리는 동안 DbContext를 계속 유지하는 것은 낭비입니다 ...

에 따라 많은 사람들 규칙 1은 자신의 내부에 자신의 DbContexts이 "저장소 패턴" 만들고 데이터베이스 쿼리마다 새로운 인스턴스를 수 있도록 X * DbContext 의 요청에 따라

그들은 단지 데이터를 얻고 최대한 빨리 컨텍스트를 처리합니다. 이것은 많은 사람들에 의해 수용 가능한 관행으로 간주됩니다 . 이것은 최소한의 시간 동안 db 자원을 점유하는 이점이 있지만, UnitofWork캐싱 캔디 EF가 제공하는 모든 것을 분명히 희생시킵니다 .

DbContext 의 단일 다목적 인스턴스를 유지하면 캐싱 의 이점이 극대화 되지만 DbContext는 스레드로부터 안전하지 않으며 각 웹 요청이 자체 스레드에서 실행되므로 요청 당 DbContext가 가장 길어질 수 있습니다.

따라서 요청 당 1 Db 컨텍스트 사용에 대한 EF 팀의 권장 사항은 웹 애플리케이션에서 UnitOfWork가 하나의 요청 내에있을 가능성이 높으며 해당 요청에 하나의 스레드가 있다는 사실을 분명히 기반으로합니다. 따라서 요청 당 하나의 DbContext는 UnitOfWork 및 Caching의 이상적인 이점과 같습니다.

그러나 많은 경우에 이것은 사실이 아닙니다. 별도의 UnitOfWork를 로깅 하는 것을 고려 하므로 비동기 스레드 에서 요청 후 로깅을위한 새로운 DbContext 가 허용됩니다.

마지막으로 DbContext의 수명은이 두 매개 변수로 제한됩니다. UnitOfWork스레드


3
모든 공정에서 HTTP 요청은 다소 빠르게 완료되어야합니다 (몇 ms). 그것들이 그보다 길면 외부 작업 스케줄러와 같은 일부 백그라운드 처리를 수행하여 요청이 즉시 리턴되도록 생각할 수 있습니다. 즉, 아키텍처가 실제로 HTTP에 의존해서는 안됩니다. 전반적으로 좋은 대답입니다.
호감

22

DbContext가 전혀 스레드 안전하지 않기 때문에 확실합니다. 따라서 공유하는 것은 결코 좋은 생각이 아닙니다.


HTTP 요청에서 공유하는 것이 결코 좋은 생각이 아닙니까?
Andrew

2
그래 앤드류는 그게 무슨 뜻인지 컨텍스트 공유는 단일 스레드 데스크톱 앱에만 해당됩니다.
엘리자베스

10
한 요청에 대한 컨텍스트 공유는 어떻습니까? 따라서 하나의 요청에 대해 서로 다른 저장소에 액세스하고 동일한 컨텍스트를 공유하여 여러 저장소를 통해 거래를 할 수 있습니까?
Lyubomir Velchev

16

질문이나 토론에서 실제로 다루지 않은 것 중 하나는 DbContext가 변경 사항을 취소 할 수 없다는 사실입니다. 변경 사항을 제출할 수는 있지만 변경 트리를 지울 수 없으므로 요청 당 컨텍스트를 사용하는 경우 어떤 이유로 든 변경 사항을 버려야하는 경우 운이 없습니다.

개인적으로 필요할 때 DbContext 인스턴스를 만듭니다. 일반적으로 필요한 경우 컨텍스트를 다시 만들 수있는 비즈니스 구성 요소에 연결됩니다. 그렇게하면 단일 인스턴스를 강제로 사용하지 않고 프로세스를 제어 할 수 있습니다. 또한 실제로 사용되는지 여부에 관계없이 각 컨트롤러 시작시 DbContext를 만들 필요가 없습니다. 그런 다음 요청 당 인스턴스를 계속 유지하려면 CTOR에서 인스턴스를 생성하거나 (DI를 통해 또는 수동으로) 각 컨트롤러 방법에서 필요에 따라 생성 할 수 있습니다. 개인적으로 필자는 실제로 필요하지 않을 때 DbContext 인스턴스를 작성하지 않도록 후자의 방법을 사용합니다.

그것은 당신이 보는 각도에 달려 있습니다. 나에게 요청 당 인스턴스는 의미가 없었습니다. DbContext가 실제로 HTTP 요청에 속합니까? 행동의 관점에서 그것은 잘못된 곳입니다. 비즈니스 컴포넌트는 Http 요청이 아니라 컨텍스트를 작성해야합니다. 그런 다음 필요에 따라 비즈니스 구성 요소를 작성하거나 버릴 수 있으며 컨텍스트의 수명에 대해 걱정하지 않아도됩니다.


1
이것은 흥미로운 답변이며 부분적으로 귀하에게 동의합니다. 나에게 DbContext는 웹 요청에 묶일 필요는 없지만 '비즈니스 트랜잭션'과 같이 항상 하나의 '요청'으로 입력됩니다. 컨텍스트를 비즈니스 트랜잭션에 연결하면 변경 취소가 정말 이상해집니다. 그러나 웹 요청 경계에이를 포함하지 않는다고해서 BC (Business Components)가 컨텍스트를 작성해야한다는 의미는 아닙니다. 나는 그것이 그들의 책임이 아니라고 생각합니다. 대신 BC 주 주변의 데코레이터를 사용하여 범위를 적용 할 수 있습니다. 이렇게하면 코드를 변경하지 않고도 범위를 변경할 수 있습니다.
Steven

1
이 경우 비즈니스 개체에 대한 주입은 수명 관리를 처리해야합니다. 내 관점에서 비즈니스 객체는 컨텍스트를 소유하므로 수명을 제어해야합니다.
Rick Strahl

간단히 말해서 "필요한 경우 컨텍스트를 재생성하는 능력"이라고 말할 때 무엇을 의미합니까? 자신의 롤백 기능을 롤링하고 있습니까? 좀 더 정교하게 할 수 있습니까?
tntwyckoff

2
개인적으로 DbContext를 처음 시작할 때 약간 번거 롭다고 생각합니다. 데이터베이스에 도달해야한다고 보장 할 수 없습니다. 그 쪽의 상태를 변경하는 타사 서비스를 호출하고있을 수 있습니다. 또는 실제로 2 ~ 3 개의 데이터베이스를 동시에 사용하고있을 수도 있습니다. 처음에는 DbContext를 사용하지 않는 경우를 대비하여 많은 DbContext를 만들지 않습니다. 비즈니스는 작업중인 데이터를 알고 있으므로 해당 데이터에 속합니다. 필요한 경우 TransactionScope를 시작 부분에 두십시오. 모든 통화에 하나가 필요하다고 생각하지 않습니다. 자원이 필요합니다.
다니엘 로렌츠

컨테이너가 dbcontext의 수명을 제어 할 수 있는지 여부에 대한 질문은 부모 컨트롤의 수명을 때로는 부적절하게 제어합니다. 컨트롤러에 간단한 서비스 싱글 톤을 주입하려면 요청 당 의미 론으로 인해 constuctor inject를 사용할 수 없습니다.
davidcarr

10

나는 이전 의견에 동의합니다. 단일 스레드 응용 프로그램에서 DbContext를 공유하려면 더 많은 메모리가 필요하다는 것이 좋습니다. 예를 들어 Azure의 웹 응용 프로그램 (한 개의 작은 인스턴스 하나)에는 150MB의 메모리가 더 필요하며 시간당 약 30 명의 사용자가 있습니다. HTTP 요청에서 응용 프로그램 공유 DBContext

실제 이미지 예 : 응용 프로그램이 12PM에 배포되었습니다


아이디어는 한 요청에 대한 컨텍스트를 공유하는 것입니다. 다른 리포지토리와-DBSet 클래스에 액세스하고 해당 작업을 트랜잭션으로 처리하려면 좋은 솔루션이되어야합니다. 오픈 소스 프로젝트 mvcforum.com을 살펴보십시오. 그것이 그들의 작업 단위 디자인 패턴의 구현에서 이루어 졌다고 생각합니다.
Lyubomir Velchev

3

내가 좋아하는 것은 작업 단위 (사용자가 보는 것처럼-즉 페이지 제출)를 ORM 의미에서 작업 단위와 정렬한다는 것입니다.

따라서 전체 페이지 제출 트랜잭션을 트랜잭션으로 만들 수 있으며, 각각 새로운 컨텍스트를 작성할 때 CRUD 메소드를 노출하는 경우에는 수행 할 수 없습니다.


2

단일 스레드 단일 사용자 응용 프로그램에서도 단일 DbContext를 사용하지 않는 또 다른 절제된 이유는 사용하는 ID 맵 패턴 때문입니다. 이는 쿼리를 사용하거나 id로 데이터를 검색 할 때마다 검색된 엔티티 인스턴스를 캐시에 유지함을 의미합니다. 다음에 동일한 엔터티를 검색하면 동일한 세션에서 수행 한 수정 사항과 함께 엔터티의 캐시 된 인스턴스 (사용 가능한 경우)가 제공됩니다. 이는 SaveChanges 메소드가 동일한 데이터베이스 레코드의 여러 다른 엔티티 인스턴스로 끝나지 않도록하기 위해 필요합니다. 그렇지 않으면 컨텍스트가 어떻게 든 모든 해당 엔티티 인스턴스의 데이터를 병합해야합니다.

문제가되는 이유는 싱글 톤 DbContext가 결국 전체 데이터베이스를 캐시하고 메모리에 .NET 객체의 오버 헤드를 캐시 할 수있는 시한 폭탄이 될 수 있기 때문입니다.

.NoTracking()확장 방법 과 함께 Linq 쿼리 만 사용하여이 동작을 해결할 수있는 방법이 있습니다. 또한 요즘 PC에는 많은 RAM이 있습니다. 그러나 일반적으로 원하는 동작이 아닙니다.


이것은 정확하지만 가비지 콜렉터가 작동한다고 가정해야이 문제가 실제보다 더 가상이됩니다.
tocqueville

2
가비지 콜렉터는 활성 정적 / 단일 오브젝트가 보유한 오브젝트 인스턴스를 수집하지 않습니다. 그들은 힙의 2 세대에있게됩니다.
Dmitry S.

1

Entity Framework에서 특히주의해야 할 또 다른 문제는 새 엔터티 만들기, 지연로드 및 새 컨텍스트 (동일한 컨텍스트에서)를 조합하여 사용할 때입니다. IDbSet.Create를 사용하지 않는 경우 (단지 새로 작성) 해당 엔티티에서 작성된 컨텍스트에서 검색 될 때 해당 엔티티의 지연로드가 작동하지 않습니다. 예 :

 public class Foo {
     public string Id {get; set; }
     public string BarId {get; set; }
     // lazy loaded relationship to bar
     public virtual Bar Bar { get; set;}
 }
 var foo = new Foo {
     Id = "foo id"
     BarId = "some existing bar id"
 };
 dbContext.Set<Foo>().Add(foo);
 dbContext.SaveChanges();

 // some other code, using the same context
 var foo = dbContext.Set<Foo>().Find("foo id");
 var barProp = foo.Bar.SomeBarProp; // fails with null reference even though we have BarId set.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.