如何有效地在Entity Framework中设置多对多EntityCollection?

时间:2011-05-30 17:57:05

标签: entity-framework-4 linq-to-entities many-to-many entitycollection addrange

当Entity Framework为与多对多关系表连接的两个数据库表(比如说Table1和Table2)生成一个ObjectContext时,它不会为外部参照表创建一个对象,而是选择集合属性。两种关系的结束。因此,在表1中,您有EntityCollection<Table2> Table2s,而在表2中,您有EntityCollection<Table2> Table1s。在大多数情况下,这实际上非常棒......

但是,在这种情况下,我有一个整数列表,表示应该在Table1.Table2s集合中的Table2行的数据库ID。

我看不到使用实体键设置该集合的任何方法,所以我不习惯在ObjectContext中选择这些,这已经无缘无故地做了大量的工作。我让自己希望LINQ-to-Entities能够智能地推迟执行并在SQL服务器上执行所有操作(尽管我的Where使用Contains,可能会也可能不会在SQL中正确地转换为IN())。所以我可以去:

table1instance.Table2s.Clear();
var table2sToInclude = context.Table2s.Where(
  t => 
  listOfTable2DatabaseIds.Contains(t.Id));

但是没有EntityCollection<T>.AddRange(IEnumerable<T>)或任何东西,当然也没有IEnumerable<T>.ToEntityCollection<T>()扩展方法,因此我不知道此时如何处理这些结果。我所能做的只是

foreach (var table2 in table2sToInclude)
{
  table1instance.Table2s.Add(table2);
}

这似乎很荒谬,我知道会强制进行大量不必要的评估。

有没有“正确的”,或许,“不那么蹩脚”的方式来做到这一点?

1 个答案:

答案 0 :(得分:2)

没有EF不会推迟任何查询执行。没有什么比选择插入更好的了。 Linq-to-entities只是查询语言,查询的责任是执行。它与EF本身提供的持久性功能严格分开。

如果要在table1中创建现有项目与从table2退出项目之间的关系,可以使用以下代码:

using (var ctx = new YourContext())
{
    var table1 = new Table1 { Id = 123 };
    ctx.Table1s.Attach(table1);

    foreach (var table2 in table2sToInclude.Select(id => new Table2 { Id = id }))
    {
        ctx.Table2s.Attach(table2);
        order.Table2s.Add(table2);
    }
    ctx.SaveChanges();
}

此代码在表1的id为123的项目与table2sToInclude的所有Table2项目之间创建关系,而不从数据库加载任何单个记录。

是什么让你逐一添加记录&#34; lame&#34;?你了解AddRange的好处是什么?典型集合中的AddRange扩展了内部数组的容量,只是将项目复制到扩展数组。 EntityCollection不是典型的数组,必须处理每个添加的实体。因此,即使存在一些AddRange,它也会在内部迭代项目并将其处理为一个。