使用急切加载/"。包括"用自定义类型选择?

时间:2014-05-11 08:39:37

标签: c# linq entity-framework eager-loading entity-framework-6.1

这是THIS的后续问题。

我遇到了同样的问题,但解决方案对我来说不起作用 我有如下查询:

item = db.Categories
       .Include(i => i.AccessRight.Roles).Include(i => i.AccessRight.Permissions)
       .Select(i => new ContentItemWithRevision<Category, ContentRevision>()
           {
               Item = i,
               AccessRight = i.AccessRight,
               Roles = i.AccessRight.Roles,
               Permissions = i.AccessRight.Permissions,
               Revision = i.Revisions.OrderByDescending(r => r.DateCreated).FirstOrDefault()
           })
       .FirstOrDefault(c => c.Item.Id == id);

选择中的AccessRightRolesPermissions添加到&#34;技巧&#34;由于我不查询Include,因此忽略了查询中entity type的急切加载。

但这不起作用,因为我悄悄话。 item.Item.AccessRight AccessRight = i.AccessRight加载了Select,我可以在我只能传递item.Itemitem.Item.AccessRight.Rolesitem.Item.AccessRight.Permissions的视图中使用item.Roles不是(但item.PermissionInclude已正确加载。) 所以这似乎是&#34;技巧&#34;只适用于&#34;一个级别&#34;。

有没有办法解决这个问题?
现在是否有办法使用新版本的EF来使item.Item正常工作,因为这将是IMO的最佳解决方案?
或者我可以至少使用&#34;多个级别&#34;?

我目前唯一可以解决的解决方案是不通过item,而是通过item.Roles并使用item.Item.AccessRight.Roles代替item.Item.AccessRight.Roles,但这不是很直观(当一些人使用Include因为他不知道问题时崩溃)并且在我的应用程序中需要进行一些更改。 我也尝试在Select之后使用Select,但是在我entity type Category之后我再次使用了Revision

也许我的基本问题也有完全不同的解决方案:
我只想选择我的1:n及其最新Category:Revisions而不是所有修订(因为这些可能很多)。如果有一个解决方案没有我的自定义类型,我也可以使用该解决方案。

更新:
这是我的DB的简化模型:
enter image description here
因此1:1Category:AccessRightn:mAccessRights:RolesAccessRights:Permissionsvar category = db.Categories .Include(i => i.AccessRight.Roles) .Include(i => i.AccessRight.Permissions) .Include(i => i.Revisions) .FirstOrDefault(i => i.Id == id); 为{{1}}。

以下查询也可以,但获得所有修订,而不仅仅是最新版本:

{{1}}

1 个答案:

答案 0 :(得分:1)

现在你已经更新了你的问题,我可以解释你能做什么和不该做什么,以及为什么。

在您的工作查询中,您从数据库中获取整个实体(Category),其中包含所有相关的导航属性(AccesRight.RolesAccesRight.PermissionsRevisions急切地装着。到目前为止一切顺利:

var category = db.Categories
               .Include(i => i.AccessRight.Roles)
               .Include(i => i.AccessRight.Permissions)
               .Include(i => i.Revisions)
               .FirstOrDefault(i => i.Id == id);

但现在您的要求是仅加载Revisions集合中的最后一个修订版。如果你这样做,你会作弊:语义category.Revisions是&#34;此类别的所有修订&#34;。如果您使用该属性仅加载最后一个修订版,那么您将破坏该语义。即便如此,这是可能的,但不可取。但是,使用单个查询无法完成:必须完成加载所有相关实体,但Revisions,然后显式加载修订,但过滤它们,如下所示:

ctx.Configuration.LazyLoadingEnabled = false;

var catWithRev = ctx.Categories
                .Include(c => c.AccessRight.Roles)
                .Include(c => c.AccessRight.Permissions)
                //.Include(c => c.Revisions) --  not eagerly loaded
                .FirstOrDefault(i => i.Id == id);

// Explicitly load the filtered revisions
ctx.Entry(catWithRev).Collection(cwr => cwr.Revisions).Query()
                .OrderByDescending(r => r.DateCreated).Take(1)
                .Load();

现在,你有自己想要的东西,但要考虑这些因素:

  • 你应该禁用延迟加载。如果没有,您的房产可能会延迟加载,将所有修改带入房产
  • 在语义上是&#34;糟糕的&#34;因为您只有一个集合中应包含所有修订版本的最后一个修订版本。

因此,创建一个包含所有相关导航属性的对象,但修订版和最后一个修订版,如下所示会更好:

var catWithRev = ctx.Categories
                .Include(c => c.AccessRight.Roles)
                .Include(c => c.AccessRight.Permissions)
                //.Include(c => c.Revisions)
                .Select(c => new
                {
                    Category = c,
                    LastRevision = c.Revisions
                        .OrderByDescending(r => r.DateCreated)
                        .FirstOrDefault()
                })
                .FirstOrDefault(i => i.Id == id);

通过这种方式,所有数据都加载到一个查询中,并且语义正确。您可以使用匿名类型,例如示例代码,或者专门为此创建一个类。

(注意:此代码经过测试并正常运行)