2014-06-03 2 views
4

내 응용 프로그램은 Entity Framework 6.1.0 및 DbContext API를 사용합니다.DbContext.ChangeTracker.HasChanges가 매우 느립니다.

그것은 일종의 CAD 시스템이며 일부 엔지니어링 문서를 편집하기위한 것입니다. 문서의 변경 사실을 확인하려면 DbContext.ChangeTracker.HasChanges을 사용하고 있습니다.

문서에 많은 양의 데이터 (약 20-25,000 개의 항목)가있는 경우 DbContext.ChangeTracker.HasChanges매우 느림입니다. 이 코드는 "저장"명령을 활성화/비활성화하는 데 사용되므로 UI ​​스레드에서 자주 실행됩니다. 이는 애플리케이션 성능에 영향을 미친다.

private Lazy<DbContext> context; 

    public bool HasChanges 
    { 
     get 
     { 
      if (!context.IsValueCreated) 
      { 
       return false; 
      } 

      return context.Value.ChangeTracker.HasChanges(); 
     } 
    } 

일이에 :

public bool HasChanges 
    { 
     get 
     { 
      if (!context.IsValueCreated) 
      { 
       return false; 
      } 

      var objectStateManager = ((IObjectContextAdapter)context.Value).ObjectContext.ObjectStateManager; 

      return 
       objectStateManager.GetObjectStateEntries(EntityState.Added).Any() || 
       objectStateManager.GetObjectStateEntries(EntityState.Deleted).Any() || 
       objectStateManager.GetObjectStateEntries(EntityState.Modified).Any(); 
     } 
    } 

을하고 (이것은 기적이다!) 모든 것이 매우 빠르게 작동

이 나는이 조각을 다시 작성했습니다.

DbChangeTracker.HasChanges처럼 보이는 것은 최적이 아닙니다. 내가 빠진 것이 있습니까?

답변

3

첫 번째 코드 단편에서 HasChanges에 대한 호출 체인은 DetectChanges를 호출합니다. 스냅 샷 변경 추적을 사용하는 경우 DetectChanges는 추적 된 모든 엔티티를 검사하여 HasChanges가 올바른 결과를 반환하도록 변경되었는지 확인합니다.

두 번째 코드 단편은 DetectChanges를 호출하지 않고 상태 관리자에게 이미 알고있는 상태에 대해 묻습니다. 따라서 엔티티가 수정되었지만 아직 감지되지 않은 경우 두 번째 코드 단편이 잘못된 결과를 반환 할 수 있습니다.

처리 방법에는 여러 가지가 있으며 그 중 하나는 스냅 샷 변경 추적 대신 변경 내용 추적 프록시를 사용하는 것입니다. DetectChanges에 대한 블로그 시리즈를 작성하여 다양한 옵션과 절충안을 자세히 설명합니다 : http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/. 나는 당신이 당신의 어플리케이션에 가장 적합한 변경 추적의 종류에 대해 좋은 선택을 할 수 있도록 읽기를 권할 것입니다.

2

@Dennis, Detect changes는 첨부 된 모든 항목을 나열합니다. 즉, 1000 개의 항목을 추가하면 첫 번째 항목은 항목을 열거하고 두 번째 항목은 1 개의 항목을 열거합니다. 그래서 우리가 이것에 대한 수학을한다면 우리는 아래와 같이됩니다.

1 + 2 + 3 + ... + 999 + 1000 

or: 

N(N+1)/2 

귀하의 경우 N은 대략 25,000입니다. 합계 출력 액수를 상상해보십시오. 이 함수는 클래스 O (N^2)입니다. 즉, 큰 O 표기법은 많은 수의 항목을 추가하는 데 너무 오래 걸리는 이유를 설명하는 N 제곱의 복잡성입니다.

아래와 같이 코드, 즉 3 개 카테고리, 25,000 엔티티를 분리했다 라이트 삭제 &은 & 수정 그들의 총합 정지 (N + 1)/2 N 복귀 한 이전의 1 LOC에 25,000 반대이다. 따라서 작업의 효율성 비교.

objectStateManager.GetObjectStateEntries(EntityState.Added).Any() || 
       objectStateManager.GetObjectStateEntries(EntityState.Deleted).Any() || 
       objectStateManager.GetObjectStateEntries(EntityState.Modified).Any() 
+2

질문의 코드는 추가 호출과 관련이 없습니다. DetectChanges를 한 번 호출하면 많은 수의 엔티티에서 느려지지만 O (N^2)는 아닙니다. –