1

这是对THIS的后续问题。

我有大约同样的问题,但解决方案对我来说不是 100% 有效。
我有如下查询:

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

和在选择中添加到“技巧”中的急切加载,因为查询中的AccessRightsRoles被忽略,因为我不查询. PermissionsIncludeentity type

但这并不如我所愿。item.Item.AccessRightAccessRight = i.AccessRightin加载,Select并且可以在我的视图中使用,我只传入,但item.Item不是(但正确加载)。 所以看起来这个“技巧”只适用于“一个级别”。item.Item.AccessRight.Rolesitem.Item.AccessRight.Permissionsitem.Rolesitem.Permission

有没有办法解决这个问题?
现在有没有办法使用新版本的 EF 来完成这项Include工作,因为这将是 IMO 的最佳解决方案?
或者我至少可以让“多层次”的技巧发挥作用吗?

我目前唯一可以工作的解决方案是不通过item.Item,而是完整item并使用item.Roles而不是item.Item.AccessRight.Roles,但这不是很直观(因为它在某些用途时崩溃,item.Item.AccessRight.Roles因为他没有意识到问题)并且需要进行一些更改在我的整个申请中。
我也尝试过使用Includeafter Select,但这给了我一个例外,因为在Select我没有 an之后entity type

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

更新:
这是我的数据库的简化模型:
在此处输入图像描述
所以有一个1:nforCategory:Revisions1:1forCategory:AccessRightn:mforAccessRights:RolesandAccessRights:Permissions

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

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

1 回答 1

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上是“这个类别的所有修订”。如果您使用该属性仅加载最后一个修订版,那么您将破坏该语义。即便如此,这是可能的,但不可取。但是,它不能使用单个查询来完成:它必须加载所有相关实体,但是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();

现在,您拥有了您想要的东西,但请考虑以下事项:

  • 你应该禁用延迟加载。如果没有,您的属性可能会延迟加载,将所有修订都带入属性中
  • 语义上是“糟糕的”,因为您只有集合中的最后一个修订版应该包含所有修订版。

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

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

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

(注意:此代码已经过测试并且可以正常工作)

于 2014-05-29T18:05:48.203 回答