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))
。
对于 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);
如果我理解正确,您是在询问是否包含嵌套属性。如果是这样 :
.Include(x => x.ApplicationsWithOverrideGroup.NestedProp)
或者
.Include("ApplicationsWithOverrideGroup.NestedProp")
或者
.Include($"{nameof(ApplicationsWithOverrideGroup)}.{nameof(NestedProp)}")
Include(string path)
版本。
EF Core:使用“ThenInclude”加载多个级别:例如:
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author)
.ThenInclude(author => author.Photo)
.ToList();
EFCore examples on MSDN 表明您可以使用 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();
您可以进行多次 Include
调用 - 即使在 ThenInclude
之后,它也会将您“重置”回顶级实体(讲师)的级别。
您甚至可以多次重复相同的“第一级”集合 (CourseAssignments),然后使用单独的 ThenIncludes
命令访问不同的子实体。
请注意,您的实际查询必须标记到 Include
或 ThenIncludes
链的末尾。以下不起作用:
var query = _context.Instructors.AsQueryable();
query.Include(i => i.OfficeAssignment);
var first10Instructors = query.Take(10).ToArray();
强烈建议您设置日志记录,并确保您的查询不会失控,如果您包含超过一两件事。了解它的实际工作原理很重要——您会注意到每个单独的“包含”通常是一个新查询,以避免大量连接返回冗余数据。
如果您不打算实际编辑实体并重新保存,AsNoTracking
可以大大加快速度。
EFCore 5 对多组实体的查询发送到服务器的方式进行了一些更改。有 new options for Split Queries 可以使这种类型的某些查询以更少的连接更有效,但请确保了解限制 - 并启用日志记录以避免以后出现性能意外。
我为 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();
DbSet<One>().Include(x => x.Two.Three.Four.Five.Six)
,唯一的缺点是您正在计算笛卡尔积并可能增加带宽.
我还必须使用多个包含,在第三级我需要多个属性
(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......
的情况下完成吗
让我清楚地说明,如果您不介意使用字符串文字,则可以使用字符串重载来包含嵌套级别,而不管对应关系的多重性:
query.Include("Collection.Property")
query.SelectMany(x=>x.foos).Include("bar").Include("bar.docs")...
我将为我的特定问题添加我的解决方案。我需要包含两个相同级别的集合。最终的解决方案看起来像这样。
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;
这是按给定饮料配方的体积计算酒精百分比。正如你所看到的,我只是将成分集合包含了两次,然后将成分和数量包含在其中。
我想出了一个最简单的方法。您不需要安装包 ThenInclude.EF 或者您不需要对所有嵌套导航属性使用 ThenInclude。如下图所示,EF会为你照顾好休息。例子:
var thenInclude = context.One.Include(x => x.Twoes.Threes.Fours.Fives.Sixes)
.Include(x=> x.Other)
.ToList();
我有一个显示 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();
现在索引立即加载。
Include
:Db.States.Include(state => state.Cities.Select(city => city.Customers).Include(state => state.Cities.Select(city => city.Vendors)