实体框架中是否存在自动关联?

时间:2015-01-29 18:06:01

标签: c# .net 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是否已经引用了不同的Clan,如果是,则将其从该氏族的People集合中删除。

在DLINQ中,我相信他们使用EntitySet和EntityRef来实现这一目标。实体框架中是否存在等价物?

非常感谢!

2 个答案:

答案 0 :(得分:4)

我在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时,才会通过延迟加载来加载。因此,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 )

......现在将通过。

答案 1 :(得分:0)

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

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方法中显式指定外键关系。