【问题标题】:Want Entity Framework 6.1 eager loading to load only first level希望 Entity Framework 6.1 急切加载仅加载第一级
【发布时间】:2014-07-24 12:51:20
【问题描述】:

我不确定我的方法是错误的,或者这是一种默认行为,但它没有按我预期的方式工作......

这里有两个示例类...

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 属性。

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

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

【问题讨论】:

    标签: entity-framework entity-framework-6.1


    【解决方案1】:

    使用Include() 实现预加载只有在您的对象上启用延迟加载时才有效--也就是说,您的导航属性必须声明为virtual,以便 EF 代理可以用延迟加载行为覆盖它们。 否则,它们会自动加载,Include() 将不起作用。

    Person.DepartmentDepartment.People 声明为虚拟 属性后,您的代码应该可以按预期工作。

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


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

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      如何摆脱相关实体

      我不知道你需要做什么,但对于当前版本的 EF,你必须 detach the entity from the context 并手动删除相关实体。

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 我明白了。但据我所知,这是 EF 的默认行为。这就是为什么 LINQ 存在的原因,以防您想在不花费大量内存加载不必要的属性的情况下获取特定属性。
        • 通过扩展方法可以访问相同的行为,使用Select(e =&gt; new {...});。这个答案似乎错过了问题的症结。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多