【发布时间】:2011-09-21 15:09:02
【问题描述】:
流行示例:在问题跟踪器 JIRA 中,问题可以链接到其他问题。链接本身附有一些数据,尤其是类型。
例子:
问题 A -> 取决于 -> 问题 B
问题 B 依赖于 问题A
我们正在使用 EF 4.1 CodeFirst 在 C# ASP.NET MVC 应用程序中为实体引入相同类型的关系,我想知道如何最好地为这种关系建模?
详情:
这种情况有一些特殊性:
- 链接附有一些数据,因此我们不能简单地建模问题和问题之间的多对多关系。我们宁愿引入一个新的实体Link,它代表两个问题之间的关系。
- 链接,顾名思义,链接同一实体的两个实例,它是“二对多”关系(一个链接有两个问题,一个问题可以有多个链接)。
- 链接是定向的,这意味着,如果问题 A 依赖于问题 B,那么问题 B 依赖于问题 A。
我们肯定会有一个如下所示的Link实体:
public class Link
{
public int ID { get; set; }
public Issue IssueA { get; set; }
public Issue IssueB { get; set; }
public LinkType Type { get; set; }
}
问题类可能如下所示:
public class Issue
{
public int ID { get; set; }
public virtual ICollection<Link> Links { get; set; }
}
目前只有一种链接类型:依赖。因此,链接类型如下所示:
public class LinkType
{
public int ID { get; set; }
public string ForwardName { get; set; } // depends on
public string BackwardName { get; set; } // is depended on by
}
现在是个大问题:
如果我希望 EF 自动管理 Issue.Links,我必须告诉它要使用 Link 表上的哪个外键。要么我使用IssueA,要么我使用IssueB。我不能同时使用,可以吗?
我定义:
modelBuilder.Entity<Issue>().HasMany(i => i.Links).WithRequired(l => l.IssueA);
或者我定义:
modelBuilder.Entity<Issue>().HasMany(i => i.Links).WithRequired(l => l.IssueB);
可能的方法 - 我很好奇您的反馈,其中一些方法是否会导致麻烦、无法实施,或者这些方法中的任何一种是否可以被视为“最佳实践”:
- 将两个集合添加到问题,
ICollection<Link> OutgoingLinks,ICollection<Link> IncomingLinks。这样集合可以由 EF 维护,但从业务逻辑的角度来看,它们没有多大意义。 - 如果可能的话,只添加一个集合并配置 EF 4.1 以添加传入 和 传出链接。
-
只添加一个集合,自己实现:
ICollection<Link> AllLinks { return _context.Links.Where(l => l.IssueA == this || l.IssueB == this).ToList(); }这种方法的问题是域实体执行数据访问任务,这在关注点分离方面很糟糕。
还有其他的吗?
【问题讨论】:
-
只有第一个解决方案是正确的,并且只有该解决方案才能与 EF 一起使用。从业务角度来看也是正确的,因为您提到链接是定向的,因此如果问题依赖于另一个问题或另一个问题依赖于这个问题,这是一个很大的区别。
-
@Ladislav:谢谢。我知道我可以指望你回答 :-) - 关于业务角度:使用链接对象的属性仍然可以检索方向信息,但我总是希望获得 all 的列表问题的链接,而不仅仅是传入或传出集(我认为...)
标签: many-to-many entity-framework-4.1 ef-code-first