Entity Framework 中是否有自动关联?

Are there Automatic Associations in Entity Framework?

我似乎记得(也许记错了)DLinq 提供了自动关联。我似乎找不到如何在 EF 中启用或完成此操作。

示例:

public partial class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Clan Clan { get; set; }
}

public partial class Clan
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Person> People { get; set; }
}

如果这些是我的实体,那么我想执行这样的操作:

var p = new Person() { Name = "Tom" };
var c = new Clan() { Name = "SomeClan" };
p.Clan = c;
ASSERT( c.People.First() == p )

或者

var p = new Person() { Name = "Tom" };
var c = new Clan() { Name = "SomeClan" };
c.People.Add(p);
ASSERT( p.Clan == c )

此外,如果我使用了 c.People.Add 方法,它应该检查 p.Clan 是否已经引用了不同的氏族,如果是,则将其从该氏族的人员集合中删除。

在 DLINQ 中,我相信他们使用 EntitySet 和 EntityRef 来完成此任务。 Entity Framework 中是否存在等效项?

非常感谢!

有很多方法可以做到这一点。最简单的方法是将 ClanId 属性 添加到您的 Person class 然后使用:

public partial class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ClanId {get; set;}    // You might need to make it virtual. Not sure.
    public virtual Clan Clan { get; set; }
}

public partial class Clan
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Person> People { get; set; }
}

这将指示 EF 通过名称 ClanId 创建一个外键。然后您就可以使用以下语法:

var p = new Person() { Name = "Tom" };
var c = new Clan() { Name = "SomeClan" };
p.ClanId = X;  // Replace X by a suitable Id.
ASSERT( c.People.First() == p )

想法是确保正确创建外键关系。 EF 能够多次推断出这一点,尤其是在一对多关系中,但在某些情况下却不能。像这样明确指定它将使其在所有情况下都有效。

当您尝试将新人与现有氏族相关联时,这还有其他好处。在某些情况下,EF 认为氏族是新的并尝试插入它。使用这种方法,您将不会遇到这个问题。

另一种方法是在重写的 OnModelCreating 方法中明确指定外键关系。

我在 LINQ-toSQL(以前称为 DLINQ)中尝试了您的代码,但断言永远不会通过。明显的原因是上下文甚至不知道新对象,所以它不可能将它们关联起来。但是,即使您将对象插入上下文 c.People 也不会被填充

var p = new Person() { Name = "Tom" };
var c = new Clan() { Name = "SomeClan" };
p.Clan = c;
context.People.InsertOnSubmit(p);
context.Clans.InsertOnSubmit(c);
ASSERT( c.People.First() == p ) // Still no items in c.People

即使在 SubmitChanges 之后,c.People 也没有任何项目。只有当您在新的上下文中从数据库中重新获取新的 Clan 时,c.People 才会通过延迟加载来加载。所以这些 "automatic associations" 在 LINQ-to-SQL.

中不存在

在 Entity Framework 中有一个名为 relationship fixup 的进程运行 very frequently。在此过程中,EF 扫描主键值和外键值,并在它们匹配时填充导航属性(如 c.People)。

如果你在 EF 中做同样的事情:

var p = new Person() { Name = "Tom" };
var c = new Clan() { Name = "SomeClan" };
p.Clan = c;
context.People.Add(p); // Also adds c to the context

...Add 方法将触发 DetectChanges,进而触发关系修复,并且

ASSERT( c.People.First() == p )

...现在将通过。