[英]EF4 Code First - Many to many relationship issue
將一個關系保存為多對多關系時,我的EF Code First模型遇到了一些麻煩。 我的模特:
public class Event
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Event> Events { get; set; }
}
在我的控制器中,我將一個或多個TagViewModels映射為Tag類型,然后將其發送到我的服務層以實現持久性。 目前,通過檢查實體,標記同時具有ID和名稱 (在我的視圖中,ID為隱藏字段,名稱為文本框)
當我現在嘗試將標簽添加到事件中時,會出現問題。 讓我們來看看以下情形:
該事件已經存在於我的數據庫中,並且說它已經具有相關的標簽C#, ASP.NET
如果現在將以下標簽列表發送到服務層:
ID Name
1 C#
2 ASP.NET
3 EF4
並通過首先從數據庫中獲取事件來添加它們,以便從DbContext獲得實際的事件,然后我只需
myEvent.Tags.Add
問題是在SaveChanges()
我的數據庫現在包含這組標記:
ID Name
1 C#
2 ASP.NET
3 EF4
4 C#
5 ASP.NET
即使我保存的標簽在保存時設置了它的ID(盡管我沒有從數據庫中獲取它)
我想我知道您的代碼中發生了什么。 讓我用一個簡單的例子來解釋我的觀點:
using (var context = new Context())
{
// Just let assume these are your tags received from view model.
var csharp = ...;
var aspnet = ...;
var ef4 = ...;
// Now you load Event
var e = context.Events.Where(e => e.Id == someId);
// Ups first access to Tag collection triggers lazy loading which
// is enabled by default so, all current tags are loaded
e.Tags.Add(csharp);
e.Tags.Add(aspnet);
e.Tags.Add(ef4);
// Now e.Tags.Count == 5 !!! Why?
context.SaveChanges();
}
第一個問題:因為在Event
實例頂部創建的動態代理使用HashSet
作為Tags
所以它檢查集合中是否已存在添加的實體。 如果不是,則添加該實體,否則跳過該實體。 為了能夠正確執行此檢查, 您必須在Tag中實現Equals等於GetHashCode ! 因此,因為您沒有執行此操作,所以它將添加的標簽作為帶有臨時鍵的新標簽,並使用自動生成的鍵將它們添加到Tags
表。
第二個問題:即使實現Equals
和GetHashCode
您也只能解決C#和ASP.NET標記的重復性。 目前,上下文尚未跟蹤EF4標簽,因此該標簽仍被視為新標簽。 您必須通知上下文EF4標簽存在於數據庫中。 因此,在觸發“ Tags
集合上的延遲加載之前,讓“ Attach
所有標記Attach
到上下文”。 默認情況下,將實體附加到上下文Unchanged
其狀態設置為Unchanged
:
using (var context = new Context())
{
foreach (var tag in TagsFromView)
{
context.Attach(tag);
}
// Now you load Event
var e = context.Events.Where(e => e.Id == someId);
foreach(var tag in TagsFromView)
{
// First access will trigger lazy loading but already
// attached instances of tags are used
e.Tags.Add(tag);
}
// Now you must delete all tags present in e.Tags and not
// present in TagsFromView
context.SaveChanges();
}
如果您未在視圖中創建新標簽,則此方法有效。 如果您也想這樣做,則一定不要在上下文中附加新標簽。 您必須在現有標簽和新標簽之間進行區分(例如,新標簽可以具有Id = 0)。
您需要從數據庫獲取標簽,否則EF會將其視為新項目並覆蓋ID。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.