IQueryable<Organization> query = context.Organizations;
Func<Reservation, bool> predicate = r => !r.IsDeleted;
query.Select(o => new {
Reservations = o.Reservations.Where(predicate)
}).ToList();
このクエリは「Internal .NET Framework Data Provider error 1025」例外をスローしますが、以下のクエリはスローしません。
query.Select(o => new {
Reservations = o.Reservations.Where( r => !r.IsDeleted)
}).ToList();
正しい述部を構築するためにいくつかのifステートメントをチェックする必要があるため、最初のものを使用する必要があります。この状況ではifステートメントを使用できないことを知っているため、デリゲートをパラメーターとして渡します。
最初のクエリを機能させるにはどうすればよいですか?
上記の答えは正しいですが、selectステートメントの後に使用する場合は、AsQueryable()
を明示的に呼び出す必要があります。そうしないと、コンパイラーは、Func
を期待するIEnumerableメソッドを使用しようとしていると想定しますExpression<Func>
ではありません。
これはおそらく、元のポスターの問題でした。さもないと、コンパイラは、Func
ではなくExpression<Func>
を探しているとほとんどの場合文句を言います。
デモ:以下は失敗します:
MyContext.MySet.Where(m =>
m.SubCollection.Select(s => s.SubItem).Any(expr))
.Load()
以下は機能しますが:
MyContext.MySet.Where(m =>
m.SubCollection.Select(s => s.SubItem).AsQueryable().Any(expr))
.Load()
報奨金(ラット!)を作成した後、 この答え が見つかりました。これで問題が解決しました。 (私の問題には.Any()
呼び出しが関係していましたが、この質問よりも少し複雑です...)
要するに、ここにあなたの答えがあります:
IQueryable<Organization> query = context.Organizations;
Expression<Func<Reservation, bool>> expr = r => !r.IsDeleted;
query.Select(o => new { Reservations = o.Reservations.Where(expr) })
.ToList();
ローカル変数expr
が必要な理由の説明については、参照された回答を読んでください。また、戻り型Expression<Func<Reservation, bool>>
の別のメソッドを直接参照することはできません。
Pingを送ってくれてありがとう。結局、私は正しい軌道に乗っていたと思います。
とにかく、繰り返しになりますが、 LINQ to Entities (コメントで自分の思考プロセスに混乱が生じたときに修正してくれたJon Skeetに感謝します)は Expression Trees ; QueryProvider
でラムダ式をSQLに変換する投影 が許可されます。
レギュラーFunc<>
は、 LINQ to Objects。
したがって、この場合、Entity Frameworkを使用しているときは、EFのIQueryable
に渡される述語はすべてExpression<Func<>>
。
別のシナリオでこの問題を経験しました。
Expression
述語でいっぱいの静的クラスがあり、これを組み合わせてEFクエリに渡すことができます。それらの1つは:
_ public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
IEnumerable<EventEnums.AttendeeStatus> statuses)
{
return ce => ce.Event.AttendeeStatuses
.Where(a => a.ClientId == ce.Client.Id)
.Select(a => a.Status.Value)
.Any(statuses.Contains);
}
_
これは、Contains
メソッドグループ呼び出しが原因で1025エラーをスローしていました。エンティティフレームワークはExpressionを予期していましたが、method groupを検出したため、エラーが発生しました。ラムダ(暗黙的に式にキャストできる)を使用するようにコードを変換すると、エラーが修正されました。
_ public static Expression<Func<ClientEvent, bool>> ClientHasAttendeeStatus(
IEnumerable<EventEnums.AttendeeStatus> statuses)
{
return ce => ce.Event.AttendeeStatuses
.Where(a => a.ClientId == ce.Client.Id)
.Select(a => a.Status.Value)
.Any(x => statuses.Contains(x));
}
_
余談:その後、式をce => ce.Event.AttendeeStatuses.Any(a => a.ClientId == ce.Client.Id && statuses.Contains(a.Status.Value));
に簡略化しました
同様の問題がありました。次のようなViewModelのライブラリ:
public class TagViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public static Expression<Func<SiteTag, TagViewModel>> Select = t => new TagViewModel
{
Id = t.Id,
Name = t.Name,
};
これは動作します:
var tags = await db.Tags.Take(10).Select(TagViewModel.Select)
.ToArrayAsync();
しかし、これはコンパイルされません:
var post = await db.Posts.Take(10)
.Select(p => new {
Post = p,
Tags = p.Tags.Select(pt => pt.Tag).Select(TagViewModel.Select)
})
.ToArrayAsync();
2番目の.Select
は混乱であるため、最初の1つは実際にはICollectionから呼び出されますが、これはIQueryableではないため、最初のExpressionをExpression<Func...
ではなくプレーンなFunc
として消費します。このページで説明したように、それはIEnumerable<...
を返します。 .AsQueryable()
が救助に:
var post = await db.Posts.Take(10)
.Select(p => new {
Post = p,
Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
.Select(TagViewModel.Select)
})
.ToArrayAsync();
しかし、それは新しい、奇妙な問題を作成します:内部フレームワーク...エラー1025を取得するか、.Post
プロパティが完全にロードされたpost変数を取得しますが、.Tags
プロパティにはLazy-読み込み中。
解決策は、匿名クラスの使用を終了することにより、タグの戻り値の型を制御することです。
public class PostViewModel
{
public Post Post { get; set; }
public IEnumerable<TagViewModel> Tags { get; set; }
これを選択すると、すべて機能します:
var post = await db.Posts.Take(10)
.Select(p => new PostViewModel {
Post = p,
Tags = p.Tags.Select(pt => pt.Tag).AsQueryable()
.Select(TagViewModel.Select)
})
.ToArrayAsync();