我在查詢中包含導航屬性Include
,以便稍後不會延遲加載。但是,當我使用Select
投影創建匿名包裝對象時,它不起作用。EF:使用「選擇」投影創建包裝對象時,「包含」導航屬性
讓我看看簡單的例子。 實體:
public class UserEntity {
public string Name {get;set;}
public virtual ICollection<UserEntity> Friends { get; set; }
}
查詢:
var entry = _dbCtx
.Users
.Include(x => x.Friends)
// Select here is simplified, but it shows the wrapping
.Select(user => new {
User = user
})
.First();
// Here we have additional lazy loaded DB call
var friends = entry.User.Friends.Select(x => x.Name).ToList();
而且我也看到生成的SQL,不包括該導航屬性:
SELECT
[Limit1].[Name] AS [Name],
FROM (SELECT TOP (1)
[Extent1].[Name] AS [Name]
FROM [dbo].[Users] AS [Extent1]
) AS [Limit1]
是否有可能到Include
導航屬性Friends
in這種情況下,以便User
將獲得沒有延遲加載的數據?
,我也期待這個工作:
var entry = _dbCtx
.Users
.Select(user => new {
User = user
})
.Include(x => x.User.Friends)
.First();
但是,讓一個例外:
InvalidOperationException異常:在查詢的結果類型既不是的EntityType,也不與實體元素類型CollectionType 。包含路徑只能爲具有這些結果類型之一的查詢指定。
有一些解決方法我來,但他們莫名其妙地棘手:
除了屬性添加到我們的匿名對象
Select
:var entry = _dbCtx .Users .Select(user => new { User = user, UsersFriends = user.Friends }) .First(); // manually copy the navigation property entry.User.Friends = user.UsersFriends; // Now we don't have any addition queries var friends = entry.User.Friends.Select(x => x.Name).ToList();
地圖還用戶一個匿名對象,然後將屬性映射到C#中的
UserEntity
。var entry = _dbCtx .Users .Select(user => new { User = new { Name = user.Name, Friends = user.Friends } }) .Take(1) // Fetch the DB .ToList() .Select(x => new { User = new UserEntity { Name = x.Name, Friends = x.Friends } }) .First(); // Now we don't have any addition queries var friends = entry.User.Friends.Select(x => x.Name).ToList();
所以,現在,有一個Friends
一個LEFT OUTER JOIN
,但都解決方法是不太好:
1)附加屬性和副本不是一個乾淨的方式。
2)我的UserEntity有更多的其他屬性。另外,每次我們添加新的屬性,我們都應該修改這裏的選擇器。
是否有某種方式來實現導航屬性,包括從第一個樣本?
感謝您的閱讀,我希望有人對此有所瞭解。
編輯:
我將擴展實體和查詢,以顯示真正的用例。
實體
public class UserEntity {
public string Name {get;set;}
public int Score {get;set;}
public virtual ICollection<UserEntity> Friends { get; set; }
}
查詢
var entry = _dbCtx
.Users
.Include(x => x.Friends)
.Select(user => new {
User = user,
Position = _dbCtx.Users.Count(y => y.Score > user.Score)
})
.First();
你的樣品將作爲我們創建的'C#'側(查詢後)的包裝對象,而不是用'sql'。但我在'db'級別需要它。原因:我用'Select'執行額外的子查詢。有趣的是,查看我的第一個解決方法,雖然我們在查詢中使用了'user.Friends',但是我們必須在實現後將Property複製回實體,否則我們仍然會進行延遲加載。 – tenbits
爲什麼你需要投影到數據庫查詢中的匿名類型?據我所知,你最終會得到同樣的結果。或者你在投射你希望投影到SQL的_additional_方法('Where','OrderBy'等)? –
看到我的文章編輯,我爲用戶執行子查詢,並且它應該在數據庫中完成,因爲它遍歷每個用戶。所以由於性能的原因,我不能用'c#'來做到這一點。 – tenbits