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


144

このクエリでは:

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システムに基本的な制限があるのですか?


IEnumrableオブジェクトを新しい変数に格納してから、variable.last()を返します。それが動作します。
Ali.Rashidi 2016年

回答:


220

その制限は、最終的にはそのクエリをSQLに変換する必要があり、SQLにはSELECT TOP(T-SQLの場合は)SELECT BOTTOM(aはありません)が含まれるという事実に帰着します

簡単な方法がありますが、降順でを実行するだけFirst()です。

編集: 他のプロバイダーはの異なる実装を持つ可能性がありますがSELECT TOP 1、Oracleではおそらくもっと似たものになりますWHERE ROWNUM = 1

編集:

別の効率の悪い代替手段- これはお勧めしません!- .ToList()以前.Last()にデータを呼び出すことで、その時点までに構築されたLINQ To Entities式がすぐに実行され、次に.Last()が機能.Last()します。代わりにLINQ to Objects式。(そして、あなたが指摘したように、それは何千ものレコードを取り戻し、決して使用されないCPUマテリアライズオブジェクトの負荷を浪費する可能性があります)

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


そして、LINQ To SQLはこのシナリオをどのように扱いますか?
ベバクア、2011

@ニールはい、私はToListを呼び出すことができることを知っていますが、データベースから数千のレコードを取得して5つのレコードにフィルターするだけではありません
bevacqua

2
クエリが小さな結果を返すことがわかっている場合、呼び出しToListはそれほど悪くありません。
ジャスティンスカイズ2013

35

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

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

14

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());
}

1
.FirstOrDefault()の代わりに.Take(1).Single()を使用する理由はありますか?
Tot Zam

2
シングル()が例外をスローするので、アイテム数が正確に1でない場合@TotZam有効な置換は、その場合の1次回()だろう
MEMark

0

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

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

0

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

ここで必要なのは、「最後の」レコードが「最初」になり、FirstOrDefaultを使用できるようにデータを並べ替えることです。通常、データベースには「最初」や「最後」などの概念はありません。テーブルに最後に挿入されたレコードが「最後」になるとは限りません。

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

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

-2

AsEnumerable()Select関数が機能する前に、単一の関数を追加しました。
例:

return context.ServerOnlineCharacters
    .OrderByDescending(p => p.ServerStatus.ServerDateTime)
    .GroupBy(p => p.RawName).AsEnumerable()
    .Select(p => p.FirstOrDefault());

参照:https : //www.codeproject.com/Questions/1005274/LINQ-to-Entities-does-not-recognize-the-method-Sys


リンクからの作業コードを回答に組み込むことをお勧めします。リンクのみの回答は否定的な注目を集めます。問題を解決および解決するために見つけたコードを追加して、完全な回答を提供してください。これにより、将来404エラーが発生してリンクが機能しなくなる問題が解決されます。
Studocwho

1
私の答えに例を追加しました
Artem Levitin

この回答の欠点は、「AsEnumerable」サーバー側の前にすべての結果が表示され、最初の結果が選択されることです。これは非常に望ましくない場合があります。(このような状況では、サーバー側に20k +レコードが持ち込まれ、結果が20秒以上かかっていました。DB側に戻すと、結果が1秒未満で返されました)
TChadwick
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.