2015-10-06 45 views
2

所以我是新來EF(我使用EF6),我有問題了解這個概念,我試圖更新實體與子集合。關於跟蹤EF(更新實體與子集合)

這裏是我的實體類:

public class TimeSheet 
{ 
    public int TimeSheetID { get; set; } 
    public virtual ICollection<TimeSheetDetail> Details { get; set; } 
} 

public class TimeSheetDetail 
{ 
    public int TimeSheetDetailID { get; set; } 
    public int TimeSheetID { get; set; } 
    public virtual TimeSheet TimeSheet { get; set; } 
} 

我的更新方法:

public void Update(TimeSheet obj) 
{ 
    var objFromDB = Get(obj.TimeSheetID); 
    var deletedDetails = objFromDB.Details.Except(obj.Details).ToList(); 

    _dbContext.Entry(obj).State = EntityState.Modified; 

    //track if details exist 
    foreach (var details in obj.Details) 
    { 
     _dbContext.Entry(details).State = details.TimeSheetDetailID == 0 ? EntityState.Added : EntityState.Modified; 
    } 

    //track deleted item 
    foreach (var deleted in deletedDetails) 
    { 
     _dbContext.Entry(deleted).State = EntityState.Deleted; 
    } 
} 

public TimeSheet Get(object id) 
{ 
    //return _timeSheet.Find(id); //Without AsNoTracking I got error 
    int x = Convert.ToInt32(id); 
    return _timeSheet.AsNoTracking().SingleOrDefault(a => a.TimeSheetID == x); 
} 

上面的代碼給我Attaching an entity of type 'ClassName' failed because another entity of the same type already has the same primary key value。所以我的問題是:

  1. 如何更新與EF的子集合?意思是我需要在數據庫中不存在的情況下添加新數據,否則進行更新,或者如果數據庫在POST中刪除,則從數據庫中刪除。

  2. 如果我不使用AsNoTracking(),它會拋出Saving or accepting changes failed because more than one entity of type 'ClassName' have the same primary key value。我注意到,如果我沒有使用AsNoTracking(),我的DbSet將數據從DB添加到它的Local屬性,導致EF框架拋出錯誤,因爲它認爲我有重複的數據,導致錯誤是由我的DbSet造成的。這實際上是如何工作的?

  3. 正如你可以看到我試圖比較objFromDbobj來檢查用戶是否刪除其中的一個細節,以便我可以從數據庫中刪除它。相反,我從收集結果中得到了一堆DynamicProxies。什麼是DynamicProxies,它是如何工作的?

  4. EF上有沒有好的文章或101教程?到目前爲止,我只看到一個簡單的,不能幫助我的情況,我四處張望,找到一個混合的答案如何做的東西。說實話,在這一點上,我希望我會用經典的ADO.Net而不是EF。

回答

1

爲了更好地理解實體框架,認爲DbContext爲您的應用程序和數據庫之間的代理。 DbContext將緩存所有內容,並將使用緩存值中的每一位數據,除非您告訴它不要這樣做。

爲1:這取決於您的環境,如果你的DbContext沒有設置選擇和更新的entites你可以簡單地只需撥打SaveChanges和您的數據將被保存之間。如果您的DbContext處置,您可以從上下文中分離出實體,更改數據,重新附加它們並將EntityState設置爲已修改。

我不能給你一個100%肯定的答案,因爲我半年前停止使用實體框架。但我知道更新複雜關係是一種痛苦。

For 2.:命令AsNoTracking告訴EF不跟蹤對此查詢中的實體所做的更改。例如,從數據庫中選擇5個時間片,更改第一個實體中的某些值並刪除最後一個。 DbContext知道第一個實體被更改,最後一個被刪除,如果您撥打SaveChangesDbContext將自動更新第一個實體,刪除最後一個實體並保持其他實體不變。現在,您嘗試自己更新實體,並將第一個實體再次附加到DbContext。

DbContext現在將有兩個具有相同鍵的實體,這會導致您的異常。

For 3.DynamicProxies是實體框架用來跟蹤這些實體變化的對象。

對於4:選中此link,也有關於實體框架6(標題:「編程實體框架」)一本好書

+0

對於答覆號2,如果EF能自動跟蹤內部的變化實體,爲什麼它不能檢測到子集合中的更改?例如,如果我在我的Update方法中使用這些代碼_timeSheet.Attach(obj); _dbContext.Entry(obj).State = EntityState.Modified;',它不會識別集合屬性中的更改。 – warheat1990

+0

實體框架無法跟蹤導航屬性內的更改。導航屬性可以通過延遲加載進行加載,也可以爲空,如果您使用空集合更新實體,則實體框架不知道該做什麼。 – JoeJoe87577