[英]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);
選擇中的AccessRight
, Roles
和Permissions
被添加到“技巧”中,作為查詢中的Include
的急切加載被忽略,因為我不查詢entity type
。
但這在我發誓時不起作用。 item.Item.AccessRight
由Select
的AccessRight = i.AccessRight
加載,並且可以在我只傳遞item.Item
視圖中item.Item
,但是item.Item.AccessRight.Roles
和item.Item.AccessRight.Permissions
是否(但正確加載了item.Roles
和item.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:Revisions
為1:n
,對於Category:AccessRight
為1:1
,對於AccessRights:Roles
和AccessRights:Permissions
為n: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.Roles
, AccesRight.Permissions
和Revisions
)。 到現在為止還挺好:
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.