如何解决EF 4.1加载已过滤的子集合不适用于多对多
|| 我一直在研究在显式加载相关实体时应用过滤器,并且无法使其用于多对多关系。 我创建了一个简单的模型: 简要描述;简介:Student
可以包含许多many1ѭ,而Course
可以具有许多Students
。
Student
可以做成许多many5ѭ,但是a5ѭ只能做成一个one0ѭ。
因此,我们得到的是Students
和Courses
之间的多对多关系,以及Student
和Presentations
之间的多对多关系。
我还添加了一个彼此相关的Student
,一个Course
和一个Presentation
。
这是我正在运行的代码:
class Program
{
static void Main()
{
using (var context = new SportsModelContainer())
{
context.Configuration.LazyLoadingEnabled = false;
context.Configuration.ProxyCreationEnabled = false;
Student student = context.Students.Find(1);
context.
Entry(student).
Collection(s => s.Presentations).
Query().
Where(p => p.Id == 1).
Load();
context.
Entry(student).
Collection(s => s.Courses).
Query().
Where(c => c.Id == 1).
Load();
// Trying to run Load without calling Query() first
context.Entry(student).Collection(s => s.Courses).Load();
}
}
}
加载演示文稿后,我发现Presentations
的计数从0变为1 :。但是,对ѭ1进行相同操作后,没有任何变化:
因此,我尝试加载课程而不调用Query
,它可以按预期工作:
(我删除了Where
子句以进一步强调该点-最后两次加载尝试仅因\“ Query()\”调用而不同)
现在,我看到的唯一区别是,一种关系是一对多的,而另一种是多对多的。这是EF错误,还是我缺少某些东西?
顺便说一句,我检查了最后两次Course
加载尝试的SQL调用,它们均100%相同,因此似乎是EF无法填充集合。
解决方法
我可以准确地再现您描述的行为。我的工作是这样的:
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Include(c => c.Students)
.Where(c => c.Id == 1)
.Load();
我不知道为什么当我们只想加载一个集合时,为什么我们也必须被迫加载多对多关系的另一端(Include(...)
)。对我来说,确实感觉像是个错误,除非我错过了此要求的一些隐藏原因,该原因在任何地方都没有记录。
编辑
另一个结果:您的原始查询(不包括)...
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.Load();
...实际上是将课程加载到DbContext
中
var localCollection = context.Courses.Local;
...显示。 ID为1的课程确实在此集合中,这意味着:加载到上下文中。但这不在学生对象的子级集合中。
编辑2
也许这不是一个错误。
首先:我们在这里使用两个不同版本的two26ѭ:
DbCollectionEntry<TEntity,TElement>.Load()
Intellisense说:
从中加载实体集合
数据库。请注意,
在上下文中已经存在不存在
覆盖了
数据库。
对于其他版本(IQueryable
的扩展方法)...
DbExtensions.Load(this IQueryable source);
... Intellisense说:
枚举查询,以便
服务器查询,例如
System.Data.Entity.DbSet,
System.Data.Objects.ObjectSet,
System.Data.Objects.ObjectQuery,
和其他查询结果
将被加载到相关的
System.Data.Entity.DbContext,
System.Data.Objects.ObjectContext或
客户端上的其他缓存。这是
等效于调用ToList然后
丢掉列表而没有
实际创建
清单。
因此,在此版本中,不能保证填充子集合,仅保证将对象加载到上下文中。
问题仍然存在:为什么要填充Presentations
集合,而不填充Courses
集合。我认为答案是:由于关系跨度。
关系跨度是EF中的一项功能,它可以自动修复上下文中或刚加载到上下文中的对象之间的关系。但这并非对所有类型的关系都如此。仅当一端的多重性为0或1时才会发生。
在我们的示例中,这意味着:当我们将ѭ11加载到上下文中(通过过滤的显式查询)时,EF还将ѭ5实体的外键加载到ѭ0实体-\“ transparently \”,这意味着,无论FK在not模型中作为属性公开。这个加载的FK允许EF识别加载的Presentations
属于上下文中已经存在的Student
实体。
但这不是Courses
集合的情况。课程没有“ 0”实体的外键。中间有多对多联接表。因此,当我们加载Courses
EF时,它不会识别那些课程属于上下文中的Student
,因此不会将导航集合固定在Student
实体中。
出于性能原因,EF仅针对引用(而非集合)执行此自动修复:
为了固定关系,EF透明地
重写查询带来
所有关系的关系信息
的多重性为0..1或1
另一端换一种说法
实体的导航属性
参考。如果一个实体有
与多重性的关系
大于1,EF将不会恢复原状
关系信息,因为它可以
与性能相比
带一个外国人一起
其余记录。带来
关系信息意味着检索全部
记录具有的外键。
引用Zeeshan Hirani的EF深入指南第128页。
它基于EF 4和ObjectContext,但我认为这在EF 4.1中仍然有效,因为DbContext主要是ObjectContext的包装。
不幸的是,使用Load
时要记住相当复杂的东西。
还有另一个
因此,当我们要显式加载多对多关系的一个过滤面时,我们该怎么办?也许只有这样:
student.Courses = context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.ToList();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。