同一实体的多对多集合,具有双向关系

Many-to-many collection of same entity, with two-way relationship(同一实体的多对多集合,具有双向关系)
本文介绍了同一实体的多对多集合,具有双向关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Suppose I have a widget entity, and I want to track other widgets that are adjacent to each. If the first widget is adjacent to the second widget, then the inverse is also true—the second is adjacent to the first.

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

Ideally, I would have a single collection on the entity, and could fluently configure the entity for this sort of a relationship.

public class Widget
{
    // ...

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

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

However, when I try that...

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

...Entity Framework 一点也不喜欢.

...Entity Framework doesn't like it at all.

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

The navigation property 'Adjacent' declared on type 'Widget' cannot be the inverse of itself.

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

Is there a way to configure the entity that achieves this goal, or am I going to be stuck creating parent/child collection navigation properties or separate relationship containers?

推荐答案

你需要在小部件内部引入另一个集合,类似的.

You need to introduce another collection inside the widget, something like.

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

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

By default with no fluent-api configuration, this code only will create a container table of WidgetWidgets in the database that contains two columns Widget_Id and Widget_Id1.

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

But you need to be consistent to only use one of the collection to make an adjacent relationship. If you use AdjacentTo collection to make an adjacent relationship.

widget1.AdjacentTo.Add(widget2);

保存后widget1.AdjacentTo会有widget2widget2.AdjacentFrom会有widget1.p>

After being saved widget1.AdjacentTo will have widget2 and widget2.AdjacentFrom will have widget1.

Widget_Id   Widget_Id1
    2           1

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

But if you input again with AdjacentFrom collection to make an adjacent relationship.

widget1.AdjacentFrom.Add(widget2);

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

After being saved widget1.AdjacentFrom and widget1.AdjacentTo will have widget2. Same thing happens with widget2.

Widget_Id   Widget_Id1
    2           1
    1           2

复合唯一键不能阻止插入第二条记录,因为第二条记录不被视为重复行.但是有一个变通方法是添加一个检查约束,你可以在迁移中添加这个约束.

Composite unique key can't prevent second record to be inserted, because the second record is not considered as duplicate row. But there is a workaround by adding a check constraint, you can add this constraint in the migration.

Sql("alter table WidgetWidgets add constraint CK_Duplicate_Widget check (Widget_Id > Widget_Id1)");

<小时>

要选择所有相邻的,您可以添加另一个集合,例如.


To select all adjacent you can add another collection, something like.

[NotMapped]
public ICollection<Widget> Adjacent
{
   get { return (AdjacentFrom ?? new Widget[0]).Union((AdjacentTo ?? new Widget[0])).Distinct().ToArray(); }
}

<小时>

添加检查约束后,您可以使用此扩展来添加或删除相邻的.


After adding check constraint, then you can use this extension to add or remove adjacent.

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

这篇关于同一实体的多对多集合,具有双向关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)