照会のナビゲーションプロパティを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
この場合、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();
地図ものユーザーDBレベルの匿名オブジェクトを作成し、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は他の多くのプロパティを持っています。さらに、新しいプロパティを追加するたびに、ここでセレクタも変更する必要があります。
最初のサンプルを含むナビゲーションプロパティを実現する方法はありますか?
読んでいただきありがとうございます。私は誰かがこれについての手掛かりを持っていることを願っています。
EDIT:
私は本当のユースケースを示すために、エンティティおよびクエリーを拡張します。
エンティティ
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' 'と:あなたはEFクエリの外のオブジェクト(複数可)をカプセル化した場合にどのような。しかし、私は 'db'レベルでそれを必要としました。理由:私は 'Select'で追加の副問い合わせを実行します。面白いことに、私の最初の回避策を見てください。クエリーで 'user.Friends'を使用していますが、Materialをマテリアライゼーション後にエンティティにコピーしなければなりません。 – tenbits
なぜDBクエリで匿名型に投影する必要がありますか?あなたは私が言うことができる限り、同じ結果をもたらします。あるいは、あなたはSQLに投影したい_additional_メソッド( 'Where'、' OrderBy'など)を投げかけていますか? –
私の投稿の編集を参照して、ユーザのサブクエリを実行します。各ユーザを繰り返し処理するので、DBで行う必要があります。パフォーマンスのために、私は 'c# 'でこれを行うことはできません。 – tenbits