簡體   English   中英

在自定義類型選擇中使用預先加載/“.include”嗎?

[英]Use eager loading / “.Include” with custom type select?

這是怎樣的一個后續問題

我有同樣的問題,但是該解決方案對我來說不是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);

選擇中的AccessRightRolesPermissions被添加到“技巧”中,作為查詢中的Include的急切加載被忽略,因為我不查詢entity type

但這在我發誓時不起作用。 item.Item.AccessRightSelectAccessRight = i.AccessRight加載,並且可以在我只傳遞item.Item視圖中item.Item ,但是item.Item.AccessRight.Rolesitem.Item.AccessRight.Permissions是否(但正確加載了item.Rolesitem.Permission )。
因此,似乎該“技巧”僅適用於“一個級別”。

有辦法解決嗎?
現在,新版本的EF是否有辦法使Include起作用,因為這將是IMO的最佳解決方案?
還是至少可以使“多層次”技巧發揮作用?

我目前可以使用的唯一解決方案是不傳遞item.Item而是傳遞完整的item並使用item.Roles而不是item.Item.AccessRight.Roles ,但這不是很直觀(因為當某些人使用item.Item.AccessRight.Roles時會崩潰item.Item.AccessRight.Roles因為他不知道問題所在),因此在我的整個應用程序中都需要進行一些更改。
我也嘗試在Select之后使用Include ,但這給了我一個例外,因為Select我不再具有entity type

對於我的基本問題,也許還有一個完全不同的解決方案:
我只想選擇我的Category和它的最新Revision ,而不是所有修訂版本(因為它們可能很多)。 如果有沒有我的自定義類型的解決方案,我也可以使用該解決方案。

更新:
這是我的數據庫的簡化模型:
在此處輸入圖片說明
因此,對於Category:Revisions1:n ,對於Category:AccessRight1:1 ,對於AccessRights:RolesAccessRights:Permissionsn:m

以下查詢也可以,但是可以獲取所有修訂,而不僅僅是最新的:

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

既然您已經更新了問題,我就可以解釋您可以做什么,應該做什么以及為什么。

在您的工作查詢中,您將從數據庫中獲取一個完整的實體( 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);

這樣,所有數據都在單個查詢中加載,並且在語義上是正確的。 您可以像示例代碼中那樣使用匿名類型,或為此專門創建一個類。

(注意:此代碼已經過測試並且可以正常工作)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM