2012-06-20 1 views
0

UserReport 엔티티에 대한 CRUD 작업을 관리하는 ReportConfigurationManager 클래스가 있습니다. 관심있는 두 가지 작업은 "Get"및 "SaveUpdate"입니다. 두 경우 모두 DbContext가 쿼리의 끝에 배치되도록 using 문에서 작업을 래핑합니다.EF 4.3의 변경 사항 유지 - 변경 추적 문제

결국 이러한 메서드는 WCF 서비스의 일부를 구성하지만 서비스 내에서 내부적으로 호출 될 수도 있습니다. 현재의 어려움은 ReportConfigurationManager를 직접 호출하는 단위 테스트 집합을 얻는 것입니다.

새로운 UserReport를 생성하고 저장할 수 있습니다. (엔티티가 데이터베이스에 이미 존재하는 여러 개의 중첩 된 객체를 가지고 있기 때문에 해결할 시간이 필요했습니다. 이전에 각 컨텍스트에 차례로 "첨부"해야했습니다. 위해 UserReport에 추가 호출하면 지금

내 문제를 해결합니다. 제대로 저장할 수 업데이트와 있습니다합니다.

를 I가 왔을 때 ReportConfigurationManager을 사용하는 모든 방법에

context.Configuration.ProxyCreationEnabled = false; 
    context.Configuration.AutoDetectChangesEnabled = false; 

가 있더라도 사용을 첨부하다 rReport, 그것은 고전적인 "ObjectStateManager에 같은 키를 가진 객체가 이미 존재합니다"(이것은 변경 추적 기능을 사용하지 못하도록하는 것이이 문제를 해결하기위한 것이라고 생각했습니다). 내가 업데이트 된 저장하기 전에 기존의 객체의 복사본을 얻을 필요 -

은 그래서 지금 내가 here

public UserReport SaveUpdateUserReport(UserReport userReport) 
    { 
     using (var context = new ReportDataEF()) 
     { 
      context.Configuration.ProxyCreationEnabled = false; 
      context.Configuration.AutoDetectChangesEnabled = false; 
      if (userReport.Id > 0) 
      { 
       { 
        UserReport oldReport = context.UserReports.Where(ur => ur.Id == userReport.Id).FirstOrDefault(); 
        context.Entry(oldReport).CurrentValues.SetValues(userReport); 
       }     
      } 
      else 
      { 
       //Need to attach everything to prevent EF trying to create duplicates in the database 
       context.ReportTopTypes.Attach(userReport.ReportTopType); 
       context.ReportWindows.Attach(userReport.ReportWindow); 
       context.ReportSortOptions.Attach(userReport.ReportSortOption); 

       foreach (var col in userReport.ReportColumnGroups) 
       { 
        context.ReportColumnGroups.Attach(col); 
       } 

       context.ReportTemplates.Attach(userReport.ReportTemplate); 

       //just add the new data 
       context.UserReports.Add(userReport); 
      } 

      context.SaveChanges(); 
     } 

     return userReport; 
    } 

내 관심사는 내 코드는 힘든 것 같다 것입니다있는 다음 코드를 사용하여 전환 한 부? 그리고 저의 새로운 저장 논리로도 확신하지 못합니다.

이 접근법이 맞습니까? 아니면 위의 글을 쓰는 더 좋은 방법이 있습니까? 다른 물건에가는

더 자세한 사항 :

내가 WCF를 통해 객체 그래프를 보낼테니까. 나는 다음과 같이 내가 얻을 정적 캐시 된 데이터의 집합이

public static DbQuery<ReportTemplate> IncludeAll(this DbQuery<ReportTemplate> self) 
    { 
     return self 
      .Include("ReportColumnGroups.ReportColumns.ReportColumnType") 
      .Include("ReportColumnGroups.ReportColumnType") 
      .Include("ReportSortOptions.ReportSortColumns.ReportColumn.ReportColumnType") 
      .Include("ReportSortOptions.ReportSortColumns.ReportSortType"); 
    } 

    public static DbQuery<UserReport> IncludeAll(this DbQuery<UserReport> self) 
    { 
     return self 
      .Include("ReportTemplate") 
      .Include("ReportTopType") 
      .Include("ReportWindow") 
      .Include("ReportSortOption.ReportSortColumns.ReportColumn.ReportColumnType") 
      .Include("ReportSortOption.ReportSortColumns.ReportSortType") 
      .Include("ReportColumnGroups.ReportColumns.ReportColumnType") 
      .Include("ReportColumnGroups.ReportColumnType"); 

    } 


    public static DbQuery<ReportSortOption> IncludeAll(this DbQuery<ReportSortOption> self) 
    { 
     return self 
      .Include("ReportSortColumns.ReportColumn.ReportColumnType") 
      .Include("ReportSortColumns.ReportSortType"); 
    } 

    public static DbQuery<ReportColumnGroup> IncludeAll(this DbQuery<ReportColumnGroup> self) 
    { 
     return self 
      .Include("ReportColumn.ReportColumnType") 
      .Include("ReportColumnType"); 
    } 

    public static DbQuery<ReportColumn> IncludeAll(this DbQuery<ReportColumn> self) 
    { 
     return self 
      .Include("ReportColumnType"); 
    } 

    public static DbQuery<ReportSortColumn> IncludeAll(this DbQuery<ReportSortColumn> self) 
    { 
     return self 
      .Include("ReportColumn.ReportColumnType") 
      .Include("ReportSortType"); 
    } 

:

using (var context = new ReportDataEF()) 
     { 
      context.Configuration.ProxyCreationEnabled = false; 
      context.Configuration.AutoDetectChangesEnabled = false; 
      reportConfigurationData = new ReportingMetaData() 
              { 
               WatchTypes = context.WatchTypes.ToList(), 
               ReportTemplates = context.ReportTemplates.IncludeAll().ToList(), 
               ReportTopTypes = context.ReportTopTypes.ToList(), 
               ReportWindows = context.ReportWindows.ToList(), 
               ReportSortOptions = 
                context.ReportSortOptions.IncludeAll().ToList() 
              }; 
     } 

을 다음과 같이 내가 UserReports를 검색 : 나는 열망로드를 구현했습니다

public UserReport GetUserReport(int userReportId) 
    { 
     using (var context = new ReportDataEF()) 
     { 
      context.Configuration.ProxyCreationEnabled = false; 
      context.Configuration.AutoDetectChangesEnabled = false; 
      var visibleReports = 
       context.UserReports.IncludeAll().Where(ur => ur.Id == userReportId).FirstOrDefault(); 
      return visibleReports; 
     } 
    } 

내가 걱정하는 테스트는 DB에서 기존 UserReport를 가져오고, 정적 데이터 클래스의 객체로 ReportTemplate 및 ReportColumnGroups 속성을 업데이트 한 다음 업데이트 된 UserReport를 저장하려고 시도합니다.

Ladislav의 대답 코드를 사용하면 UserReport를 첨부하려고 할 때 실패합니다. 아마도 내가 첨부 한 객체 중 하나가 이미 데이터베이스에 존재하기 때문입니다.

답변

1

예 다른 방법이 있습니다. 먼저 EF가 부분적으로 첨부 된 객체 그래프를 지원하지 않는다는 것을 알아야한다고 생각합니다. 따라서 AttachAdd은 그래프에서 아직 컨텍스트에 의해 추적되지 않은 모든 엔티티를 첨부하거나 추가하는 부작용이 있습니다. 이렇게하면 삽입 코드가 훨씬 단순 해집니다.

public UserReport SaveUpdateUserReport(UserReport userReport) 
{ 
    using (var context = new ReportDataEF()) 
    { 
     context.Configuration.ProxyCreationEnabled = false; 
     context.Configuration.AutoDetectChangesEnabled = false; 

     // Now all entities in the graph are attached in unchanged state 
     context.ReportTopTypes.Attach(userReport); 

     if (userReport.Id > 0 && 
      context.UserReports.Any(ur => ur.Id == userReport.Id)) 
     { 
      context.Entry(userReport).State = EntityState.Modified; 
     } 
     else 
     { 
      context.Entry(userReport).State = EntityState.Added; 
     } 

     context.SaveChanges(); 
    } 

    return userReport; 
} 

이것은 원래 코드와 같습니다. 사용자 보고서를 다시로드하지 마십시오. DB에 존재 여부 만 확인하면됩니다. 이 코드에는 많은 문제가 있습니다. 예를 들어 다른 관련 객체를 변경 한 경우 현재 상태가 Unchanged이므로 데이터베이스에 유지되지 않습니다. 관계를 변경해야하는 경우 훨씬 더 복잡 할 수 있습니다.

+0

개체 그래프에서 변경되는 유일한 개체는 UserReport 자체이지만 ReportColumnGroup 클래스와 수 많은 관계가 있습니다. db의 ReportColumnGroups 집합은 변경되지 않지만 Report에서 ReportColumnGroups를 추가하거나 컬렉션에서 제거 할 수 있으므로 UserReports와의 관계가 유지됩니다. – BonyT

+0

나는 당신이 한 일을 시도했지만 Attach에 실패했다고 생각했습니다. 많은 반복을 거쳤습니다. 그래서 당신이 위에서 뒀던 것을 정확하게 시도해 볼 수 있습니다. – BonyT

+0

예 - 오류와 함께 실패합니다. 동일한 키를 가진 객체가 이미 ObjectStateManager에 있습니다. 내가 컨텍스트를 실행하면 .UserReports.Attach (userReport); 위의 코드에 대한 자세한 내용을 추가하겠습니다. – BonyT