如何在实体框架中有效地设置多对多EntityCollection?
当实体框架为与多对多关系表连接的两个数据库表(假设 Table1 和 Table2)生成 ObjectContext 时,它不会为外部参照表创建对象,而是选择在其任一端创建集合属性的关系。因此,在 Table1 上,您有 EntityCollectionEntityCollection
。在大多数情况下,这实际上非常好...
但是,在这种情况下,我有一个整数列表,表示应该位于 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
或任何东西,也没有 IEnumerable
当然是扩展方法,所以我现在不知道如何处理这些结果。我所能做的就是
foreach (var table2 in table2sToInclude)
{
table1instance.Table2s.Add(table2);
}
这看起来很荒谬,而且我知道这会迫使很多不必要的评估。
有没有一种“正确”或者“不那么蹩脚”的方法来做到这一点?
When Entity Framework generates an ObjectContext for a two database tables (let's say Table1 and Table2) connected with a many-to-many relationship table, it doesn't create an object for the xref table, opting instead for collection properties on either end of the relationship. So on Table1 you have EntityCollection<Table2> Table2s
and on Table2 you have EntityCollection<Table2> Table1s
. In most cases that's actually pretty great...
However, in this scenario, I have a list of integers that represent the database IDs of the Table2 rows that should be in the Table1.Table2s collection.
I can't see any way to just set that collection using the entity keys, so I'm stuck selecting these into the ObjectContext, which is already a ton of work to do for no reason. I let myself hope that LINQ-to-Entities will intelligently defer the execution and perform it all on the SQL server like I would like (though my Where uses Contains, which may or may not be correctly translated to IN() in SQL). So I can go as far as:
table1instance.Table2s.Clear();
var table2sToInclude = context.Table2s.Where(
t =>
listOfTable2DatabaseIds.Contains(t.Id));
But there's no EntityCollection<T>.AddRange(IEnumerable<T>)
or anything, nor is there an IEnumerable<T>.ToEntityCollection<T>()
extension method of course, so I don't know what to do with these results at this point. All I can do is
foreach (var table2 in table2sToInclude)
{
table1instance.Table2s.Add(table2);
}
which seems ridiculous and I know will force a lot of unnecessary evaluation.
Is there a "correct", or, perhaps, "less lame" way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
没有 EF 不会推迟任何查询执行。没有什么比从选择插入更好的了。 Linq-to-entities 只是查询语言,查询的职责是执行。它与 EF 本身提供的持久性功能严格分开。
如果要在 table1 中的现有项目和 table2 中的退出项目之间创建关系,可以使用如下代码:
此代码在 Table1 的 id 为 123 的项目与 table2sToInclude 中的所有 Table2 项目之间创建关系,而不从数据库加载任何单个记录。
是什么让一一添加记录变得“蹩脚”?您知道
AddRange
有什么好处吗?典型集合中的AddRange
扩展了内部数组的容量,只需将项目复制到扩展数组即可。EntityCollection
不是典型的数组,它必须处理每个添加的实体。因此,即使存在一些AddRange
,它也会在内部迭代项目并逐一处理它们。No EF will not defer any query execution. There is nothing like insert from select. Linq-to-entities is just query language and responsibility of query is to execute. It is strictly separated from persistence functionality offered by EF itself.
If you want to create relations between existing item from table1 and exiting items from table2 you can use code like this:
This code creates relation between Table1's item with id 123 and all Table2's items from table2sToInclude without loading any single record from the database.
What makes adding records one by one "lame"? Do you understand what is benefit of
AddRange
?AddRange
in typical collection extends capacity of internal array and just copy items to extended array.EntityCollection
is not typical array and it must process each added entity. So even if there will be someAddRange
it will internally iterate items and process them on by one.