6

我不确定我正在以错误的方式接近,或者这是一种默认行为,但它没有按照我期望的方式工作......

这是两个示例类...

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Department Department { get; set; }
}

第二个是部门

public class Department
{
    public string Name { get; set; }

    public List<Person> People { get; set; }
}

上下文配置

public MyDbContext() : base("DefaultConnection") 
{
    this.Configuration.ProxyCreationEnabled = false;
    this.Configuration.LazyLoadingEnabled = false; 
}

public DbSet<Person> People { get; set; }
public DbSet<Department> Departments { get; set; }

我正在尝试加载姓氏来自“史密斯”的人

var foundPeople 
        = context
              .people
              .Where(p => p.LastName == "Smith");

上面的查询加载 foundPeople 只有 FirstName 和 LastName 没有 Department 对象。这是一个正确的行为,因为我的 LazyLoading 已关闭。这也是意料之中的。

现在在与 Eager loading Department 的另一个查询中,

var foundPeople 
        = context
              .people
              .Where(p => p.LastName == "Smith")
              .Include(p => p.Department);

上面的查询加载 foundPeople 与 FirstName、LastName、Department 与 Department->Name 以及 Deparment->People(该部门中的所有人,我不想要,我只想加载第一级 Included 属性。

我不知道这是有意的行为还是我犯了一些错误。

有没有办法只加载第一级包含的属性,而不是完整的图表或所有级别的包含属性。

4

3 回答 3

3

仅当在对象上启用延迟加载时,使用Include()来实现预先加载才有效--也就是说,您的导航属性必须声明为virtual,以便 EF 代理可以使用延迟加载行为覆盖它们。 否则,它们将急切地自动加载,并且Include()没有任何效果。

一旦您将Person.Department和声明Department.People虚拟属性,您的代码应该可以按预期工作。

非常抱歉,我原来的回答基本上是完全不正确的。我没有足够仔细地阅读您的问题,实际上对于急切的行为是不正确的。不知道我在想什么(或谁赞成?)。首屏下方的真实答案:


使用您发布的示例模型(进行必要的修改:实体的键并this从上下文构造函数中删除“”)我无法准确地 重现您的问题。但我不认为它正在做你认为它正在做的事情。

当您急切地加载部门(或显式加载,使用context.Entry(...).Reference(...).Load())时,更仔细地检查您的结果:集合中有元素Department.People,但不是所有的人员,只有在查询本身中加载的人员。我想你会在最后一个片段中找到!foundPeople.SelectMany(p => p.Department.People).Any(p => p.LastName != "Smith") == true. 也就是说,他们都不是“史密斯”。

我不认为有任何办法解决这个问题。Entity Framework 没有显式或急切地加载 People 集合(您可以Include(p => p.Department.People)这样做)。由于模型中的循环关系,它只是将加载的对象链接到它们的相关对象。此外,如果在同一上下文中有多个查询加载其他人员,它们也将链接到对象图中。

(顺便说一句:在这种简化的情况下,代理创建和延迟加载配置是多余的——实体上都没有启用,因为它们都没有延迟或代理(虚拟)属性——一件事我确实第一次做对了。)

于 2014-06-04T02:46:39.973 回答
2

通过设计,DbContext完成所谓的“关系修复”。由于您的模型具有关于哪些是实体之间的关系的信息,因此每当在上下文中附加或修改实体时,EF 将尝试“修复”实体之间的关系。

例如,如果您在上下文中加载具有 FK 的实体,该 FK 指示它是已附加到上下文的另一个实体的子级,它将被添加到现有实体的 children 集合中。如果您进行任何更改(更改 FK、删除实体等),关系将自动修复。这就是另一个答案所解释的:即使您使用不同的查询单独加载相关实体,它们也会附加到它们所属的子集合中。

无法禁用此功能。查看与此相关的其他问题:

如何摆脱相关实体

我不知道您需要做什么,但是使用当前版本的 EF,您必须从上下文中分离实体并手动删除相关实体。

另一种选择是使用 AutoMapper 或 ValueInjecter 进行映射,以摆脱关系修复。

于 2014-06-10T09:54:34.683 回答
-2

您可以尝试使用 LINQ 查询,以便仅选择所需的字段。我希望这会有所帮助。

于 2014-06-04T02:01:26.910 回答