ChatGPT解决这个技术问题 Extra ChatGPT

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

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))
@BobHorn,我有同样的问题。在我的情况下,嵌套深入到多层,我设法做了一个你指出的包含。在生成的 SQL 中,我可以看到所有列都以不同的别名返回,如 c1、c2 之类的。我的问题是,我如何从我的所有包含中形成一个嵌套的 DTO 集合:(.. 可能你可以自己拿上面的例子,因为我们正在返回所有没有任何自定义 DTO 的列(它本身就是 DTO 的集合)

B
Bob Horn

对于 EF 6

using System.Data.Entity;

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

确保添加 using System.Data.Entity; 以获取接受 lambda 的 Include 版本。

对于 EF 核心

使用新方法 ThenInclude

using Microsoft.EntityFrameworkCore;

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

我不能在 ApplicationsWithOverrideGroup 上执行 Include()。它不会出现在智能感知中。
啊,但是您提供的链接似乎提供了答案。让我试试这个:先包含一个集合,然后再包含一个集合:query.Include(e => e.Level1Collection.Select(l1 => l1.Level2Collection))。
请记住在 usings 中包含 System.Data.Entity。否则 Intellisense 只会为您提供该方法的 Include(string path) 版本。
@Adeem 您需要为每个属性调用 IncludeDb.States.Include(state => state.Cities.Select(city => city.Customers).Include(state => state.Cities.Select(city => city.Vendors)
你可以做 Db.States.Include(s => s.Cities).ThenInclude(c => c.Customers)。诀窍是 Intellisense 不会在第二个包含属性上为您提供下拉列表,而是继续前进并输入它。它将建立和工作!这只是智能感知中的一个错误。注意 - 仅适用于 EF Core。
t
tchelidze

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

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

或者

.Include("ApplicationsWithOverrideGroup.NestedProp")  

或者

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

谢谢,我可以试试。我希望能够保持强类型化并避免使用字符串文字。但是,如果必须这样做...
你很亲密。我可能不清楚 ApplicationsWithOverrideGroup 是一个列表。感谢您的帮助!
@Judo,我有同样的问题。在我的情况下,嵌套深入到多层,我设法做了一个你指出的包含。在生成的 SQL 中,我可以看到所有列都以不同的别名返回,如 c1、c2 之类的。我的问题是,我如何从我的所有包含中形成一个嵌套的 DTO 集合:(.. 可能你可以自己拿上面的例子,因为我们正在返回所有没有任何自定义 DTO 的列(它本身就是 DTO 的集合)
请记住在 usings 中包含 System.Data.Entity。否则 Intellisense 只会为您提供该方法的 Include(string path) 版本。
您好,如果对于 EF 核心,这确实有效。Include(x => x.ApplicationsWithOverrideGroup.NestedProp) 如果是这样,那么使用 Include / ThenInclude 有什么意义,因为它们都可以工作并产生相同的 SQL。我错过了什么吗?
M
Michael Freidgeim

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

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

看起来这只是 EF Core
仅供参考:VS2017 智能感知不适用于 .ThenInclude。只需输入您认为应该的方式,错误突出显示就会消失。
我想强调@JohnWrensby 的评论,Intellisense 有时可能需要特别长时间来处理这些 ThenInclude ,这对于新用户来说可能会很混乱。我也遇到过没有正确处理简单 Include lambda 表达式的情况,直到您只需键入并编译它,而忽略 VS 中显示的“错误”。
@Pac0 你拯救了我的一天。挣扎着看孩子的物品,不能。
S
Simon_Weaver

EFCore examples on MSDN 表明您可以使用 IncludeThenInclude 做一些相当复杂的事情。

这是一个很好的例子,说明你可以得到多么复杂(这是一个链式语句!):

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();

您可以进行多次 Include 调用 - 即使在 ThenInclude 之后,它也会将您“重置”回顶级实体(讲师)的级别。

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

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

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

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

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

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

EFCore 5 对多组实体的查询发送到服务器的方式进行了一些更改。有 new options for Split Queries 可以使这种类型的某些查询以更少的连接更有效,但请确保了解限制 - 并启用日志记录以避免以后出现性能意外。


有没有办法在没有你重复的情况下同时获得 Enrollment 和 Departments 。包括 CourseAssignment 和 Course? (到目前为止,似乎 Api 可以使用 .ThenInclude 更深入,或者使用 .Include 回到顶层,但没有什么可以保持在同一级别?)
如果您想要延迟加载,请继续关注 EF Core 2.1 blogs.msdn.microsoft.com/dotnet/2018/02/02/…,但如果您只想在同一级别加载更多内容,我认为这是设计使然。我不确定你在想什么 - 这样做不需要太多额外的东西,它大大减少了从数据库返回的内容。一个实体可能只有一两个“相同级别”的东西,但对于一个大型项目,它也可能有 50 个,显式使您的应用程序更快。
这很好地解释了 Include 再次将级别“重置”回初始级别的概念。帮助我了解包容系统的层次结构。干杯!
M
Michael Freidgeim

我为 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();

包是 available on GitHub


嗨,我在运行时遇到异常,无法将 IncludableQueryable 转换为 IncludableQueryable
我首先使用 db,并且我修改了 tt 文件以获取我所有实体的 ObservableCollections,欢迎提供任何帮助。
@lenny32 这个扩展有什么要注意的吗?
请注意,如果您要导航到的属性与您从中导航的 DbSet 是一对一的,则不需要这样做,并且您可以链接 DbSet<One>().Include(x => x.Two.Three.Four.Five.Six),唯一的缺点是您正在计算笛卡尔积并可能增加带宽.
d
dnxit

我还必须使用多个包含,在第三级我需要多个属性

(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();

这可能对某人有帮助:)


这可以在不重复 .Include(x => x.Shifts.Select(r => r.Rate).Select(rt => rt...... 的情况下完成吗
好吧,这取决于你想去多深
m
mrmashal

让我清楚地说明,如果您不介意使用字符串文字,则可以使用字符串重载来包含嵌套级别,而不管对应关系的多重性:

query.Include("Collection.Property")

这种方法有助于我弄清楚如何在 VB 中对其进行编码,因为在谷歌搜索数小时后我无法找到任何地方。
这对我很有用,我经常使用它!!!它甚至可以与 .SelectMany 语句结合使用:query.SelectMany(x=>x.foos).Include("bar").Include("bar.docs")...
D
Darth Scitus

我将为我的特定问题添加我的解决方案。我需要包含两个相同级别的集合。最终的解决方案看起来像这样。

var recipe = _bartendoContext.Recipes
    .Include(r => r.Ingredients)
    .ThenInclude(r => r.Ingredient)
    .Include(r => r.Ingredients)
    .ThenInclude(r => r.MeasurementQuantity)
    .FirstOrDefault(r => r.Id == recipeId);
if (recipe?.Ingredients == null) return 0m;
var abv = recipe.Ingredients.Sum(ingredient => ingredient.Ingredient.AlcoholByVolume * ingredient.MeasurementQuantity.Quantity);
return abv;

这是按给定饮料配方的体积计算酒精百分比。正如你所看到的,我只是将成分集合包含了两次,然后将成分和数量包含在其中。


S
Siddarth Tamagond

我想出了一个最简单的方法。您不需要安装包 ThenInclude.EF 或者您不需要对所有嵌套导航属性使用 ThenInclude。如下图所示,EF会为你照顾好休息。例子:

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

不,你不能用集合来做到这一点。它仅在所有属性都是引用时才有效。你的命名表明相反。
M
Marek Pio

我有一个显示 MbsNavigation.Name 的索引页面,它是作为外键加载的固件对象。固件对象很大,因此通过 Internet 加载索引页面需要几分钟。

BatterySystem = await _context.BatterySystems.Include(b => b.MbsNavigation)

这是仅加载 Firmware.Name 的解决方案:

BatterySystem = await _context.BatterySystems
.Include(b => b.MbsNavigation)
.Select(b => new BatterySystem() 
{
    Name = b.Name,
    MbsNavigation = new Firmware() { Name = b.MbsNavigation.Name },
})
.ToListAsync();

现在索引立即加载。