2015-01-20 3 views
4

저는 데스크톱 응용 프로그램에서 MVVM 디자인 패턴이있는 EF6 + WPF를 사용하고 있습니다. 나는 또한 DI 컨테이너로 Autofac을 사용하고 있습니다.EF에서 이전 값을 반환합니다.

EF 컨텍스트 수명 관리에 대해 많이 읽었으며 단일보기 모델 인스턴스에 대해 EF 컨텍스트 인스턴스를 하나만 사용하기로 결정했습니다. 이 접근법에 대한 몇 가지 흥미로운 기사를 발견 했으므로 EF 컨텍스트를 관리하는 것이 좋은 방법 일뿐입니다. Autofac을 사용하여 EF 수명을 관리하므로 새로운 뷰 모델을 만들 때마다 새로운 EF 컨텍스트가 하나만 만들어집니다.

물론, 문제가 생겼습니다. 대부분의 EF 쿼리는 올바르게 작동하지만 다음 쿼리는 항상 오래된 (캐시 된) 값을 반환합니다. 나는이 질문을 내가 버튼을 '실행'밀어마다 전화, 그래서 난 항상 코드를

this.context.Entry(entity).Reload(); 

을 다음과 같이 엔티티를 다시로드 할 수 있습니다 알고

this.context.someTable.Where(arg => arg.value == "value").Single(); 

단일 뷰/뷰 모델에 따라 많은 사형 집행이있다 하지만 제게는 좋은 해결책이 아닙니다. 또한 현재 컨텍스트를 처리하고 다음 쿼리 이전에 다시 작성하면 항상 현재 값을 받게된다는 것을 알고 있습니다. 그러나이 접근법은 하나의 뷰 모델 접근법 당 하나의 컨텍스트와 충돌합니다.

EF 캐싱 문제를 피하고 여전히 우수한 성능을 유지하려면 어떻게 수정해야합니까? 방법 힘 EF 데이터베이스에 쿼리를 다시 쿼리하고 결과를 캐시하지 않는 다음

+0

MVVM 컨트롤러의 someTable 부분입니까? 또는이 컨트롤러가 다른 테이블에서 데이터를 읽는 중입니까? 이 창을 열고 다른 창에서 데이터를 변경 한 다음이 창에서 업데이트 된 데이터가 보이지 않는 것 같습니다. 우리는 DB Read 구문의 컨텍스트와 someTable의 관련성을 명확히 할 필요가 있습니다. – Todd

+0

MVVM 로직을 DB 구조와 분리하려고 시도하므로 매우 자주 단일 MVVM이 여러 테이블에서 데이터를 읽습니다. MVF 계층에서 EF 엔티티를 사용하지 않고 대신 bussiness 객체/모델 객체를 사용합니다. 내 현재 문제는 DB에 새 비즈니스 개체를 저장하는 것입니다. 나는 'var entity = this.context.someTable.Where (arg => arg.value == "value")의 현재 값을 기반으로 한 어떤 인덱스 (DB 인덱스가 아님)를 계산해야한다. 엔티티 (증분)를 갱신해야합니다. 물론 다른 앱의 다른 사용자가 동일한 작업을 수행하면 EF 컨텍스트가 이전의 '엔터티'(EH 캐싱으로 인해)를 반환합니다. – rraszewski

+0

@Todd가 답변을주었습니다. 수명이 긴 EF 컨텍스트를 현실적으로 기대할 수 없습니다. 자신의 상황에서 다른 PC의 다른 응용 프로그램에서 다른 사용자가 현재 추적중인 엔티티를 수정했음을 알 수 있습니다. * 다시로드하지 않으면 컨텍스트가 db로 돌아가고 다시로드됩니다. 그러나 당신은 어떤 이유로 그것을하고 싶지 않습니다. – Mashton

답변

5

당신은 상황을

을 지속해서는 안 난 당신이 하나의 공유 컨텍스트를 포기 추천 할 것입니다. 최근에 큰 WPF 응용 프로그램에 대해이 작업을 수행했습니다. EF 컨텍스트는 작업 단위로 설계되었으므로이를 사용해야하며 .Dispose()으로 전화해야합니다. 관계 속성을 열심히 읽어야 할 경우 .Include() 힌트를 사용해야합니다. using 블록에서 컨텍스트를 구성하여 범위를 잃는 위치를 알 수 있고 컨텍스트가 삭제되었는지 확인할 수 있습니다.

EF의 성능은 내부 캐시 및 상태를 참조해야하므로 실제로 줄어들 수 있습니다. 공유 컨텍스트를 사용하면 대량 데이터 삽입 패턴이 저하되는 것을 발견했습니다. EF는 RDBMS뿐만 아니라 수행도하지 않습니다.

경험했듯이 캐시 된 엔티티에서 컨텍스트를 유지하고 이익을 얻을 수 있지만 시스템의 특성과 사용자 요구 사항으로 인해 캐시가 더 이상 도움이되지 않습니다. 백업 RDBMS는 충분히 빠릅니다. EF 2 차 수준 캐싱 및 ASP를 포함하여 어떤 방식 으로든 캐시하는 즉시.NET 출력 캐싱)을 사용하면 캐시 된 엔터티를 만료시키는 방법을 즉시 계획해야합니다. 이렇게하면 코더에게 더 많은 작업이 추가되고 시스템에 장애를주는 새로운 방법이 생깁니다.

예를 들어, EF의 이점은 관계 특성의 자동 해결이라는 점을 고려하십시오. 캐시 된 데이터와 유효하지 않은 데이터가 충돌 할 때까지 데이터 그래프를 완벽하게 파악할 수 있습니다. 이러한 상황에서는 이러한 항목을 검색하기 전에 캐시를 만료시키기가 어렵습니다.

하지만 당신이 정말로 마이크로 소프트/구성 방법을 권장하는 구조를 변경하지 않으려면 당신은 업데이트

에 다시로드해야합니다. 모든 열린 컨텍스트 (생성시 정적 컬렉션에 추가, 처 리시 제거, 종료 자 패턴으로 다시 확인, 처 리시 finalizer 억제)를 추적하고 저장 파이프 라인에 일부 일반 코드를 구현하는 것이 좋습니다 (몇 가지 방법이 있습니다 이 작업은 모든 열린 컨텍스트에서 엔터티를 다시로드하려고 시도합니다. 이것은 EF 엔티티 캐시를 만료시키기위한 사전 예방적인 방법입니다. 이렇게하면 큰 컬렉션의 실적에 영향을 줄 수 있지만 저장된 모든 개체를 처리하는 대신 처리 할 엔터티의 허용 목록이나 블랙리스트를 가질 수 있습니다.

개인적으로 나는 (짧은 수명의 컨텍스트로의 재구성) 변경을했기 때문에 개인적으로, 코드 유지 관리 및 시스템 안정성면에서 큰 이점이 있습니다.

+0

그리고 나에게 좋은 소리 ... – rraszewski

3

:

this.context.someTable.AsNoTracking().Where(arg => arg.value == "value").Single(); 

중요한 메서드 호출이 AsNoTracking

+0

'AsNoTracking'은 엔티티를 수정하고 싶기 때문에 제 문제를 해결하지 못하고 'AsNoTracking'을 추가하면 레코드가 업데이트되지 않습니다. – rraszewski

+0

아, 그래. 그런데 왜 DBContext를 뷰 모델의 수명주기 동안 처리합니까? –

+0

나는 처분하지 않는다. 나는 뷰 모델이 사는 한 같은 맥락을 가지고있다. 그래서 몇몇 연산 중에 dbcontext는 캐시 된 엔티티를 가지며 이전 값을 반환하는 이유가 있습니다. – rraszewski

0

입니다 당신이 MVVM을 사용하는 경우에 당신은 할 수 있습니다 :보기를 속성 유형 EntityViewModel (엔터티의 래퍼)을 사용하여 뷰 모델에 바인딩하십시오. 모든 변경 사항은 즉시 EntityViewModel에 나타납니다. 변경 내용을 취소하려면 EntityViewModel.Undo() 메서드를 호출합니다. 엔터티에 변경 내용을 적용하려면 EntityViewModel.Apply()를 호출합니다. 그런 다음 DbContext.SaveChanges() 메서드를 호출 할 수 있습니다.

public class Entity 
{ 
    public string Id { get; set; } 
    public string State { get; set; } 
} 

public class EntityViewModel : ViewModelBase 
{ 
    private string _state; 

    public EntityViewModel(Entity entity) 
    { 
     Entity = entity; 
     _state = entity.State; 
    } 

    public string State 
    { 
     get { return _state; } 
     set 
     { 
      if (value == _state) 
       return; 
      _state = value; 
      base.OnPropertyChanged("State"); 
     } 
    } 

    public Entity Entity {get; private set; } 

    public void ApplyChanges() 
    { 
     Entity.State = _state; 
    } 

    public void Undo() 
    { 
     State = entity.State; 
    } 
} 

이것은 MVVM에 적합한 책임 부서입니다.

+0

다른 애플리케이션 인스턴스의 사용자가 동일한 엔티티를로드하고 변경하면 어떻게해야합니까? 첫 번째 응용 프로그램은 sb가 context.SaveChanges()를 호출 할 때까지 엔티티가 변경되었음을 알 수 없습니다. – rraszewski

+0

질문을 이해하지 못했습니다. 엔티티 로딩 -> 엔티티 상태 수정 -> 같은 엔티티가 상태를 수정하지 못하면 내가 제안했거나 사용할 수 있습니다 : context.Entry (modifyEntity) .OriginalValues ​​- 이것은 데이터베이스에 의지하지 않고 원래 데이터를 반환합니다 . – sribin

+0

주기적으로 엔터티를 새로 고치려면 다른 응용 프로그램에서 변경 될 수 있으므로 엔티티를 데이터베이스에 액세스해야합니다. 이 경우 this.context.Entry (entity) .Reload() - 좋은 옵션입니다. – sribin

관련 문제