Entity framework EF 4.1加载筛选的子集合对多对多不起作用

Entity framework EF 4.1加载筛选的子集合对多对多不起作用,entity-framework,entity-framework-4.1,Entity Framework,Entity Framework 4.1,我一直在看,但无法让它在多对多关系中发挥作用 我创建了一个简单的模型: 简要说明: 一个学生可以修很多课程,课程可以有很多学生 一名学生可以做许多演示,但是演示只能由一名学生做 因此,我们拥有的是学生和课程之间的多对多关系,以及学生和演示之间的一对多关系 我还添加了一个学生、一个课程、一个演示 以下是我正在运行的代码: class Program { static void Main() { using (var context = new SportsModel

我一直在看,但无法让它在多对多关系中发挥作用

我创建了一个简单的模型:

简要说明:
一个
学生
可以修很多
课程
课程
可以有很多
学生

一名
学生
可以做许多
演示
,但是
演示
只能由一名
学生

因此,我们拥有的是
学生
课程
之间的多对多关系,以及
学生
演示
之间的一对多关系

我还添加了一个
学生
、一个
课程
、一个
演示

以下是我正在运行的代码:

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();
        }
    }
}
加载演示文稿后,我看到
演示文稿的计数从0变为1:但是,在对
课程执行相同操作后,没有任何变化:

因此,我尝试在不调用
查询的情况下加载课程,结果正如预期的那样:

(我删除了
Where
子句以进一步强调这一点-最后两次加载尝试的不同之处仅在于“Query()”调用)

现在,我看到的唯一区别是,一种关系是一对多,而另一种关系是多对多。这是EF错误,还是我遗漏了什么


顺便说一句,我检查了最近两次
课程
加载尝试的SQL调用,它们是100%相同的,因此似乎是EF未能填充集合。

我可以准确地重现您描述的行为。我的工作是:

context.Entry(student)
       .Collection(s => s.Courses)
       .Query()
       .Include(c => c.Students)
       .Where(c => c.Id == 1)
       .Load();
我不知道当我们只想加载一个集合时,为什么还要强制加载多对多关系的另一端(
Include(…)
)。对我来说,这感觉确实像一个bug,除非我错过了这个需求的一些隐藏的原因,不管是否有文档记录

编辑

另一个结果:原始查询(不包括)

。。。实际将课程加载到
DbContext
中,作为

var localCollection = context.Courses.Local;
。。。显示。Id为1的课程确实在这个集合中,这意味着:加载到上下文中。但它不在student对象的子集合中

编辑2

也许这不是一个bug

首先:我们在这里使用两个不同版本的
Load

DbCollectionEntry<TEntity, TElement>.Load()
。。。智能感知说:

枚举查询,以便 服务器查询,例如 System.Data.Entity.DbSet, System.Data.Objects.ObjectSet, System.Data.Objects.ObjectQuery, 和其他人的查询结果 将加载到关联的 System.Data.Entity.DbContext, System.Data.Objects.ObjectContext或 客户端上的其他缓存。这是 相当于调用ToList,然后 不经批准就把名单扔掉 实际创建 名单

因此,在此版本中,不保证填充子集合,只保证将对象加载到上下文中

问题是:为什么要填充
演示文稿
集合,而不是
课程
集合。我认为答案是:因为关系Span

关系范围是EF中的一个功能,它自动修复上下文中或刚刚加载到上下文中的对象之间的关系。但并非所有类型的关系都是如此。仅当一端的重数为0或1时才会发生

在我们的示例中,这意味着:当我们将
演示文稿
加载到上下文中时(通过我们过滤的显式查询),EF还将
演示文稿
实体的外键加载到
学生
实体-“透明”,这意味着,无论FK是否在not模型中作为属性公开。此加载的FK允许EF识别加载的
演示文稿
属于已在上下文中的
学生
实体

课程的情况并非如此。课程没有
学生
实体的外键。中间有多对多联接表。因此,当我们加载
课程
时,EF不会识别这些课程属于上下文中的
学生
,因此不会修复
学生
实体中的导航集合

出于性能原因,EF仅对引用(而非集合)执行此自动修复:

要修复关系,请透明地执行EF 重写查询以使 所有关系的关系信息 其上的多重数为0..1或1 另一端;换句话说 是实体的导航属性 参考资料。如果一个实体 与多重性的关系 大于1时,EF将不会恢复 关系信息,因为它可以 性能受到影响,与之相比 带着一个外国人 记录的其余部分。带来 关系信息意味着检索所有 记录中包含的外键

引自第128页,共页

它基于EF4和ObjectContext,但我认为这在EF4.1中仍然有效,因为DbContext主要是ObjectContext的包装器

不幸的是,在使用
Load
时要记住相当复杂的东西

和另一次编辑

那么,当我们想要明确地加载多对多关系的一个过滤面时,我们能做什么呢?也许只有这样:

student.Courses = context.Entry(student)
       .Collection(s => s.Courses)
       .Query()
       .Where(c => c.Id == 1)
       .ToList();

是的,有趣的发现。这会产生更多的SQL代码——基本上是为具有所有联接的学生进行新的选择(而没有
Include
的版本只使用
Courses
和映射表来获取必要的数据)。s
DbExtensions.Load(this IQueryable source);
student.Courses = context.Entry(student)
       .Collection(s => s.Courses)
       .Query()
       .Where(c => c.Id == 1)
       .ToList();