【问题标题】:Many-to-many collection of same entity, with two-way relationship同一实体的多对多集合,具有双向关系
【发布时间】:2014-08-13 21:06:37
【问题描述】:

假设我有一个小部件实体,并且我想跟踪与每个小部件相邻的其他小部件。如果第一个小部件与第二个小部件相邻,则反之亦然——第二个与第一个相邻。

理想情况下,我会在实体上有一个集合,并且可以流畅地为这种关系配置实体。

public class Widget
{
    // ...

    public virtual ICollection<Widget> Adjacent { get; set; }
}

但是,当我尝试这样做时......

modelBuilder.Entity<Widget>
            .HasMany(w => w.Adjacent)
            .WithMany(w => w.Adjacent);

...Entity Framework 根本不喜欢它。

在“Widget”类型上声明的导航属性“Adjacent”不能与自身相反。

有没有办法配置实现这个目标的实体,还是我会被困在创建父/子集合导航属性或单独的关系容器?

【问题讨论】:

    标签: c# .net entity-framework entity-framework-6


    【解决方案1】:

    您需要在小部件中引入另一个集合,例如。

    public virtual ICollection<Widget> AdjacentFrom { get; set; }
    public virtual ICollection<Widget> AdjacentTo { get; set; }
    

    默认没有fluent-api配置,这段代码只会在数据库中创建一个WidgetWidgets的容器表,包含Widget_IdWidget_Id1两列。


    但你需要保持一致,只使用其中一个集合来建立相邻关系。如果你使用AdjacentTo集合来建立相邻关系。

    widget1.AdjacentTo.Add(widget2);
    

    保存后widget1.AdjacentTo 将有widget2widget2.AdjacentFrom 将有widget1

    Widget_Id   Widget_Id1
        2           1
    

    但如果你再次输入与AdjacentFrom集合建立相邻关系。

    widget1.AdjacentFrom.Add(widget2);
    

    保存后widget1.AdjacentFromwidget1.AdjacentTo 将有widget2widget2 也会发生同样的事情。

    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);
            }
        }
    }
    

    【讨论】:

    • 认为是这样的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-13
    相关资源
    最近更新 更多