web-dev-qa-db-ja.com

LINQ To EntitiesはLastメソッドを認識しません。本当に?

このクエリでは:

_public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
    var context = DataContext.GetDataContext();
    return context.ServerOnlineCharacters
        .OrderBy(p => p.ServerStatus.ServerDateTime)
        .GroupBy(p => p.RawName)
        .Select(p => p.Last());
}
_

動作させるにはこれに切り替える必要がありました

_public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
    var context = DataContext.GetDataContext();
    return context.ServerOnlineCharacters
        .OrderByDescending(p => p.ServerStatus.ServerDateTime)
        .GroupBy(p => p.RawName)
        .Select(p => p.FirstOrDefault());
}
_

p.First()を使用して最初のクエリをミラーリングすることさえできませんでした。

なぜこのような堅牢なORMシステムに基本的な制限があるのですか?

137
bevacqua

その制限は、最終的にはそのクエリを[〜#〜] sql [〜#〜]に変換する必要があり、SQLには_SELECT TOP_(T-SQLで)があるが、 _SELECT BOTTOM_ではありません(そのようなことはありません)。

しかし、それを回避する簡単な方法があります。降順し、First()を実行します。これはあなたがしたことです。

編集:他のプロバイダーは_SELECT TOP 1_の異なる実装を持つ可能性があり、Oracleではおそらく_WHERE ROWNUM = 1_のようなものになります

編集:

もう1つの非効率的な代替手段これはお勧めしません!-.ToList()の前にデータで.Last()を呼び出すと、LINQ To Entities Expressionがすぐに実行されますそれはその時点までに構築されていて、その後.Last()が機能します。なぜなら、その時点で.Last()LINQ to Objects式のコンテキストで効果的に実行されるからです。代わりに。 (そして、あなたが指摘したように、それは何千ものレコードを取り戻し、使用されないオブジェクトを具体化するCPUの負荷を浪費する可能性があります)

繰り返しますが、この2番目の操作はお勧めしませんが、LINQ式が実行される場所とタイミングの違いを説明するのに役立ちます。

208
Neil Fenwick

Last()の代わりに、これを試してください:

model.OrderByDescending(o => o.Id).FirstOrDefault();
33
Azarsa

Last()をLinqセレクターOrderByDescending(x => x.ID).Take(1).Single()に置き換えます

あなたがLinqでそれを行うことを好めば、そのようなものはうまくいくでしょう:

public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
    var context = DataContext.GetDataContext();
    return context.ServerOnlineCharacters.OrderBy(p => p.ServerStatus.ServerDateTime).GroupBy(p => p.RawName).Select(p => p.OrderByDescending(x => x.Id).Take(1).Single());
}
14
Ema.H

これは、LINQ to Entities(および一般的なデータベース)がすべてのLINQメソッドをサポートしていないためです(詳細についてはこちらを参照してください: http://msdn.Microsoft.com/en-us/library/bb738550.aspx

ここで必要なのは、「最後の」レコードが「最初」になり、FirstOrDefaultを使用できるようにデータを順序付けることです。通常、databaseseには「最初」や「最後」などの概念はなく、最後に挿入されたレコードがテーブルの「最後」になるわけではないことに注意してください。

この方法で問題を解決できます

db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();
0
Kazem

さらに別の方法では、OrderByDescendingなしで最後の要素を取得し、すべてのエンティティをロードします。

dbSet
    .Where(f => f.Id == dbSet.Max(f2 => f2.Id))
    .FirstOrDefault();
0
Stas Boyarincev