简体   繁体   English

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

[英]Entity Framework - Include Multiple Levels of Properties

The Include() method works quite well for Lists on objects. Include() 方法非常适用于对象列表。 But what if I need to go two levels deep?但是如果我需要 go 两层深呢? For example, the method below will return ApplicationServers with the included properties shown here.例如,下面的方法将返回具有此处显示的包含属性的 ApplicationServers。 However, ApplicationsWithOverrideGroup is another container that holds other complex objects.但是,ApplicationsWithOverrideGroup 是另一个包含其他复杂对象的容器。 Can I do an Include() on that property as well?我也可以对该属性执行 Include() 吗? Or how can I get that property to fully load?或者我怎样才能让该属性完全加载?

As it stands now, this method:就目前而言,此方法:

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

Will populate only the Enabled property (below) and not the Application or CustomVariableGroup properties (below).将仅填充 Enabled 属性(下方),而不填充 Application 或 CustomVariableGroup 属性(下方)。 How do I make this happen?我该如何做到这一点?

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

For EF 6对于 EF 6

using System.Data.Entity;

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

Make sure to add using System.Data.Entity;确保using System.Data.Entity;添加using System.Data.Entity; to get the version of Include that takes in a lambda.获取Include lambda 的Include版本。


For EF Core对于 EF 核心

Use the new method ThenInclude使用新方法ThenInclude

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

If I understand you correctly you are asking about including nested properties.如果我理解正确,您是在询问包含嵌套属性。 If so :如果是这样的话 :

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

or或者

.Include("ApplicationsWithOverrideGroup.NestedProp")  

or或者

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

EF Core: Using "ThenInclude" to load mutiple levels: For example: EF Core:使用“ThenInclude”加载多个级别:例如:

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

The EFCore examples on MSDN show that you can do some quite complex things with Include and ThenInclude . MSDN 上EFCore 示例表明您可以使用IncludeThenInclude做一些非常复杂的事情。

This is a good example of how complex you can get (this is all one chained statement!):这是一个很好的例子,说明你可以得到多么复杂(这都是一个链式语句!):

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

You can have multiple Include calls - even after ThenInclude and it kind of 'resets' you back to the level of the top level entity (Instructors).您可以有多个Include调用 - 即使在ThenInclude之后,它ThenInclude将您“重置”回顶级实体(讲师)的级别。

You can even repeat the same 'first level' collection (CourseAssignments) multiple times followed by separate ThenIncludes commands to get to different child entities.您甚至可以多次重复相同的“第一级”集合 (CourseAssignments),然后是单独的ThenIncludes命令以访问不同的子实体。

Note your actual query must be tagged onto the end of the Include or ThenIncludes chain.请注意,您的实际查询必须标记在IncludeThenIncludes链的末尾。 The following does NOT work:以下不起作用:

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

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

Would strongly recommend you set up logging and make sure your queries aren't out of control if you're including more than one or two things.强烈建议您设置日志记录并确保您的查询不会失控,如果您包含的内容不止一两件。 It's important to see how it actually works - and you'll notice each separate 'include' is typically a new query to avoid massive joins returning redundant data.了解它的实际工作方式很重要 - 您会注意到每个单独的“包含”通常是一个新查询,以避免大量连接返回冗余数据。

AsNoTracking can greatly speed things up if you're not intending on actually editing the entities and resaving.如果您不打算实际编辑实体并重新保存, AsNoTracking可以大大加快速度。


EFCore 5 made some changes to the way queries for multiple sets of entities are sent to the server. EFCore 5 对将多组实体的查询发送到服务器的方式进行了一些更改。 There are new options for Split Queries which can make certain queries of this type far more efficient with fewer joins, but make sure to understand the limitations - and enable logging to avoid performance surprises later. 拆分查询新的选项,可以通过更少的联接使这种类型的某些查询更有效,但请确保了解限制 - 并启用日志记录以避免以后出现性能意外。

I made a little helper for Entity Framework 6 (.Net Core style), to include sub-entities in a nice way.我为 Entity Framework 6(.Net Core 风格)做了一个小助手,以一种很好的方式包含子实体。

It is on NuGet now : Install-Package ThenInclude.EF6它现在在 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();

The package is available on GitHub .该软件包可在 GitHub 上获得

I also had to use multiple includes and at 3rd level I needed multiple properties我还必须使用多个包含,在第 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();

This may help someone :)这可能对某人有所帮助:)

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

query.Include("Collection.Property")

I'm going to add my solution to my particular problem.我要将我的解决方案添加到我的特定问题中。 I had two collections at the same level I needed to include.我有两个需要包含在同一级别的集合。 The final solution looked like this.最终的解决方案是这样的。

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;

This is calculating the percent alcohol by volume of a given drink recipe.这是按体积计算给定饮料配方的酒精百分比。 As you can see I just included the ingredients collection twice then included the ingredient and quantity onto that.如您所见,我只包含了两次成分集合,然后将成分和数量包含在其中。

I figured out a simplest way.我想出了一个最简单的方法。 You don't need to install package ThenInclude.EF or you don't need to use ThenInclude for all nested navigation properties.您不需要安装包 ThenInclude.EF 或者不需要对所有嵌套导航属性使用 ThenInclude。 Just do like as shown below, EF will take care rest for you.如下图所示,EF会为您照顾休息。 example:例子:

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

I have an Index page that displays MbsNavigation.Name that is a Firmware object loaded as foreign key.我有一个显示 MbsNavigation.Name 的索引页面,它是作为外键加载的固件 object。 The Firmware object is big, so it takes few minutes to load Index page via an Inte.net.固件 object 很大,因此通过 Inte.net 加载索引页面需要几分钟时间。

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

This is a solution to load Firmware.Name only:这是仅加载 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();

Now the Index loads immediately.现在索引立即加载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM