实体框架-包含多个级别的属性


376

Include()方法对于对象列表非常有效。但是,如果我需要深入两个层次怎么办?例如,下面的方法将返回具有此处显示的包含属性的ApplicationServers。但是,ApplicationsWithOverrideGroup是另一个包含其他复杂对象的容器。我也可以在该属性上执行Include()吗?或如何才能完全加载该属性?

就目前而言,此方法:

public IEnumerable<ApplicationServer> GetAll()
{
    return this.Database.ApplicationServers
        .Include(x => x.ApplicationsWithOverrideGroup)                
        .Include(x => x.ApplicationWithGroupToForceInstallList)
        .Include(x => x.CustomVariableGroups)                
        .ToList();
}

将仅填充Enabled属性(在下面),而不填充Application或CustomVariableGroup属性(在下面)。我如何做到这一点?

public class ApplicationWithOverrideVariableGroup : EntityBase
{
    public bool Enabled { get; set; }
    public Application Application { get; set; }
    public CustomVariableGroup CustomVariableGroup { get; set; }
}

嗨,为什么我Expression must be a member expression在尝试此操作时会遇到异常:要包括一个集合,然后再向下一层集合:query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection))
Joe.wang 2013年

1
@BobHorn,我有同样的问题。就我而言,嵌套深入了多层,我设法做了一个包含您指出的问题。在生成的SQL中,我可以看到所有列都以不同的别名(如c1,c2)返回。我的问题是,我如何才能从我的所有include中组成一个嵌套的DTO集合: )
TechQuery

Answers:


703

对于EF 6

using System.Data.Entity;

query.Include(x => x.Collection.Select(y => y.Property))

确保添加using System.Data.Entity;以获取Includelambda 的版本。


对于EF Core

使用新方法 ThenInclude

query.Include(x => x.Collection)
     .ThenInclude(x => x.Property);

1
我无法在ApplicationsWithOverrideGroup上执行Include()。它不会出现在智能感知中。
鲍勃·霍恩

我无法使用您的修改,因为ApplicationsWithOverrideGroup是一个列表。应用程序是列表中每个项目的属性,而不是列表本身。
鲍勃·霍恩

1
啊,但是您提供的链接似乎可以提供答案。让我尝试一下:先包含一个集合,然后再向下一个集合:query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection))。
鲍勃·霍恩

60
请记住在使用中包括System.Data.Entity。否则,Intellisense将仅为您提供该方法的Include(字符串路径)版本。
OJRaqueño13年

5
@Adeem您需要Include为每个属性致电:Db.States.Include(state => state.Cities.Select(city => city.Customers).Include(state => state.Cities.Select(city => city.Vendors)
Diego Torres

72

如果我对您的理解正确,那么您正在询问是否包含嵌套属性。如果是这样的话 :

.Include(x => x.ApplicationsWithOverrideGroup.NestedProp)

要么

.Include("ApplicationsWithOverrideGroup.NestedProp")  

要么

.Include($"{nameof(ApplicationsWithOverrideGroup)}.{nameof(NestedProp)}")  

6
谢谢,我可以尝试。我希望能够保持强类型输入并避免使用字符串文字。但是如果那是必须要做的...
鲍勃·霍恩

1
你很亲近 我可能还不清楚,ApplicationsWithOverrideGroup是一个列表。感谢您的帮助!
鲍勃·霍恩

@Judo,我有同样的问题。就我而言,嵌套深入了多层,我设法做了一个包含您指出的问题。在生成的SQL中,我可以看到所有列都以不同的别名(如c1,c2)返回。我的问题是,如何从所有包含的对象中构成一个嵌套的DTO集合: )
TechQuery

2
请记住在使用中包括System.Data.Entity。否则,Intellisense将仅为您Include(string path)提供该方法的版本。
AlexMelw

52

EF核心:使用“ ThenInclude”加载多个级别:例如:

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
        .ThenInclude(author => author.Photo)
    .ToList();

53
看起来这仅是EF Core
Chris Marisic '16

27
仅供参考:VS2017智能感知不适用于.ThenInclude。只需输入您认为应该的样子,错误突出显示就会消失。
JohnWrensby

4
我想强调@JohnWrensby的评论,Intellisense有时可能花费特别长的时间来处理这些ThenInclude,这对于新用户可能会造成很大的困扰。在某些情况下,简单的“包含” lambda表达式无法正确处理,直到您只是键入并编译它,而忽略了VS中显示的“错误”。
Pac0

@ Pac0,您保存了我的一天。努力看孩子的项目,并没有。
德拉姆

28

我为Entity Framework 6(.Net Core样式)提供了一个小帮手,以一种不错的方式包含了子实体。

现在在NuGet上:Install-Package ThenInclude.EF6

using System.Data.Entity;

var thenInclude = context.One.Include(x => x.Twoes)
    .ThenInclude(x=> x.Threes)
    .ThenInclude(x=> x.Fours)
    .ThenInclude(x=> x.Fives)
    .ThenInclude(x => x.Sixes)
    .Include(x=> x.Other)
    .ToList();

该软件包可在GitHub上获得


嗨,我在运行时有一个异常,无法将IncludableQueryable <observablecollection>强制转换为IncludableQueryable <
genericcollection

我首先使用db,并且我已经修改了tt文件以获取我所有实体的ObservableCollections,欢迎任何帮助。
user2475096

2
@ lenny32这个扩展要注意什么?
亚伦·休顿

请注意,如果要导航到的属性与从中导航的DbSet是一对一的,则这不是必需的,并且可以链接DbSet<One>().Include(x => x.Two.Three.Four.Five.Six)的唯一缺点是要计算笛卡尔乘积并可能增加带宽。
John Zabroski

23

MSDN上的更多EFCore示例表明,您可以使用Include和进行一些非常复杂的操作ThenInclude

这是一个复杂程度很好的好例子(这是一条语句!):

viewModel.Instructors = await _context.Instructors

      .Include(i => i.OfficeAssignment)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)

      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)

      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

看看之后如何进行链接IncludeThenInclude以及如何“重置”您回到顶级实体(教师)的级别。

您甚至可以多次重复相同的“第一级”集合(CourseAssignments),然后通过单独的ThenIncludes命令来访问不同的子实体。

请注意,您的实际查询必须标记在IncludeThenIncludes链的末尾。以下内容不起作用:

var query = _context.Instructors.AsQueryable();
query.Include(i => i.OfficeAssignment);

var first10Instructors = query.Take(10).ToArray();

强烈建议您设置日志记录,如果要包含一两个以上的内容,请确保查询不会失控。重要的是要了解它的实际工作原理,并且您会注意到每个单独的“ include”通常是一个新查询,以避免大量联接返回冗余数据。

AsNoTracking 如果您不打算实际编辑实体并重新保存,则可以大大加快操作速度。


有没有一种方法可以让您同时获得招生和部门信息,而无需重复您的课程。包括课程分配和课程?(到目前为止,似乎Api可以使用.ThenInclude进行更深层次的处理,或者使用.include返回顶层,但是没有其他东西可以保持相同的水平了吗?)
William Jockusch

如果您想对EF Core 2.1进行延迟加载,请继续关注blogs.msdn.microsoft.com/dotnet/2018/02/02/…,但是如果您只想在相同级别加载更多,我认为这是设计使然。我不确定您在想什么-这样做不需要太多额外的操作,它可以大大减少从数据库返回的内容。一个实体可能只有一个或两个“相同级别”的东西,但对于一个大型项目,它可能也有50个,明确的实体可以使您的应用程序更快。
西蒙·韦弗

这是对Include的概念的很好的解释,该“重新”将级别重新设置为初始级别。帮助我围绕包容性体系的层次结构思考。干杯!
AFM-Horizo​​n

22

我还必须使用多个包含,并且在第3层需要多个属性

(from e in context.JobCategorySet
                      where e.Id == id &&
                            e.AgencyId == agencyId
                      select e)
                      .Include(x => x.JobCategorySkillDetails)
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.DurationType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RuleType))
                      .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt.RateType))
                      .FirstOrDefaultAsync();

这可能会帮助某人:)


1
能做到这一点而无需重复.Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt......

好吧,这取决于您想走多远
dnxit

7

让我明确指出,如果您不介意使用字符串文字,则可以使用字符串重载来包含嵌套级别,而不考虑对应关系的多重性:

query.Include("Collection.Property")

1
这种方法对我弄清楚如何在VB中进行编码很有帮助,因为在经过数小时的谷歌搜索之后我找不到任何地方。
编码器

这对我来说很棒,我经常使用它!!!它甚至可以与.SelectMany语句结合使用:query.SelectMany(x=>x.foos).Include("bar").Include("bar.docs")...
埃菲
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.