[英]Adding an existing entity to a child collection of a many-to-many relationship
[英]Many-to-many collection of same entity, with two-way relationship
假設我有一個小部件實體,並且我想跟蹤與每個小部件相鄰的其他小部件。 如果第一個窗口小部件與第二個窗口小部件相鄰,則倒數也適用-第二個窗口小部件與第一個窗口小部件相鄰。
理想情況下,我在實體上只有一個集合,並且可以為這種關系流暢地配置實體。
public class Widget
{
// ...
public virtual ICollection<Widget> Adjacent { get; set; }
}
但是,當我嘗試...
modelBuilder.Entity<Widget>
.HasMany(w => w.Adjacent)
.WithMany(w => w.Adjacent);
...實體框架根本不喜歡它。
在類型“小部件”上聲明的導航屬性“相鄰”不能與其本身相反。
有沒有一種方法可以配置實現此目標的實體,還是我將被困於創建父/子集合導航屬性或單獨的關系容器?
您需要在小部件內引入另一個類似的集合。
public virtual ICollection<Widget> AdjacentFrom { get; set; }
public virtual ICollection<Widget> AdjacentTo { get; set; }
默認情況下,沒有fluent-api配置,此代碼只會在數據庫中創建WidgetWidgets
的容器表,該表包含兩列Widget_Id
和Widget_Id1
。
但是您需要保持一致,僅使用集合之一建立相鄰關系。 如果使用AdjacentTo
集合來建立相鄰關系。
widget1.AdjacentTo.Add(widget2);
保存后, widget1.AdjacentTo
將具有widget2
, widget2.AdjacentFrom
將具有widget1
。
Widget_Id Widget_Id1
2 1
但是如果您再次使用AdjacentFrom
集合輸入來建立相鄰關系。
widget1.AdjacentFrom.Add(widget2);
保存后, widget1.AdjacentFrom
和widget1.AdjacentTo
將具有widget2
。 相同的事情發生在widget2
。
Widget_Id Widget_Id1
2 1
1 2
復合唯一鍵無法阻止插入第二條記錄,因為第二條記錄不被視為重復行。 但是有一種解決方法,即添加檢查約束,您可以在遷移中添加此約束。
Sql("alter table WidgetWidgets add constraint CK_Duplicate_Widget check (Widget_Id > Widget_Id1)");
要選擇所有相鄰對象,您可以添加另一個集合,例如。
[NotMapped]
public ICollection<Widget> Adjacent
{
get { return (AdjacentFrom ?? new Widget[0]).Union((AdjacentTo ?? new Widget[0])).Distinct().ToArray(); }
}
添加檢查約束后,您可以使用此擴展名添加或刪除相鄰項。
public static class WidgetDbExtension
{
public static void AddAdjacent(this Widget widget1, Widget widget2)
{
if (widget1.Id < widget2.Id)
{
widget1.AdjacentTo.Add(widget2);
}
else
{
widget2.AdjacentTo.Add(widget1);
}
}
public static void RemoveAdjacent(this Widget widget1, Widget widget2)
{
if (widget1.Id < widget2.Id)
{
widget1.AdjacentTo.Remove(widget2);
}
else
{
widget2.AdjacentTo.Remove(widget1);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.