Entity Frameworkを使用して列の最大値を取得するにはどうすればよいですか?


92

整数を含む列の最大値を取得するには、次のT-SQLコマンドを使用できます

SELECT MAX(expression )
FROM tables
WHERE predicates;

EntityFrameworkで同じ結果を得ることができますか?

私が次のモデルを持っているとしましょう

public class Person
{
  public int PersonID { get; set; }
  public int Name { get; set; }
  public int Age { get; set; }
}

最年長の年齢を取得するにはどうすればよいですか?

int maxAge = context.Persons.?

回答:


152

これを試して int maxAge = context.Persons.Max(p => p.Age);

そしてusing System.Linq;、ファイルの先頭にあることを確認してください


2
「System.Linqを使用する」を見逃したので、これに少し苦労しました。私のような初心者への回答にその情報を追加することを検討する必要があります:)
RagnaRock 2015年

2
いいえ問題の@RagnaRockない
krolik

3
しかし、レコードがなく、EFがエラーをスローした場合はどうなりますか。私の追加のvarmodel = db.BillOfLading.Select(x => x.No).LastOrDefault(); if(model!= null){var val = db.BillOfLading.Max(x => x.No);
HerGiz 2016

これは効率的ですか?または、エンティティフレームワークにMax関数を使用するストアドプロシージャを実行させる方がよいでしょうか?エンティティフレームワークは初めてで、本当に好奇心が強い
TemporaryFix

@Programmaticは、より効率的な理由はまったくありません。SQL Serverのバージョン<= 7の場合を除き
mxmissile

49

リストが空の場合、例外が発生します。このソリューションでは、この問題が考慮されます。

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();

7
これは受け入れられた答えでなければなりません。サーバーへのラウンドトリップは1回のみで、例外はありません。
9Rune5 2017

4
ただし、データベースからすべての列値を取得し、アプリケーション側でMaxを適用します。
スーパーダック

1
これにより、3つのサブクエリが作成されます。私は別の答えを提案しました。
jsgoupil

3
補足-これはEFコアでは機能しません。私が使用したもの:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs

11

または、これを試すことができます:

(From p In context.Persons Select p Order By age Descending).FirstOrDefault

7

フィルタを追加したい場合は、たぶん助けてください:

context.Persons
.Where(c => c.state == myState)
.Select(c => c.age)
.DefaultIfEmpty(0)
.Max();


4

あなたの列はnull許容です

int maxAge = context.Persons.Select(p => p.Age).Max() ?? 0;

あなたの列はnull許容ではありません

int maxAge = context.Persons.Select(p => p.Age).Cast<int?>().Max() ?? 0;

どちらの場合も、2番目のコードを使用できます。を使用するとDefaultIfEmpty、サーバーでより大きなクエリを実行できます。興味のある人のために、EF6に相当するものは次のとおりです。

なしでクエリ DefaultIfEmpty

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Extent1].[Age]) AS [A1]
        FROM [dbo].[Persons] AS [Extent1]
    )  AS [GroupBy1]

でクエリ DefaultIfEmpty

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Join1].[A1]) AS [A1]
        FROM ( SELECT 
            CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Age] END AS [A1]
            FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
            LEFT OUTER JOIN  (SELECT 
                [Extent1].[Age] AS [Age], 
                cast(1 as tinyint) AS [C1]
                FROM [dbo].[Persons] AS [Extent1]) AS [Project1] ON 1 = 1
        )  AS [Join1]
    )  AS [GroupBy1]

1
どうですかint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs

3

多くの人が言ったように-このバージョン

int maxAge = context.Persons.Max(p => p.Age);

テーブルが空の場合、例外をスローします。

使用する

int maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;

または

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()

あなたの2番目の答えは私には良さそうです。誰かが生成されたSQLを見るなら、2番目の答えは良いです。
DeepakSharma18年

2

VB.Netでは次のようになります

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)

2
int maxAge = context.Persons.Max(p => p.Age);

このバージョン、リストが空の場合

  • 戻り値null―null許容オーバーロードの場合
  • 例外をスローしSequence contains no elementます―null許容でないオーバーロードの場合

-

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();

このバージョンは空のリストの場合を処理しますが、より複雑なクエリを生成し、何らかの理由でEFCoreでは機能しません。

-

int maxAge = context.Persons.Max(p => (int?)p.Age) ?? 0;

このバージョンはエレガントでパフォーマンスが高く(単純なクエリとデータベースへの単一のラウンドトリップ)、EFCoreで動作します。null許容型をnull許容型にキャストし、??演算子を使用してデフォルト値を適用することにより、上記の例外を処理します。


1

選択された回答は例外をスローし、Carlos Toledoからの回答は、データベースからすべての値を取得した後にフィルタリングを適用します。

次の例では、1回のラウンドトリップを実行し、例外なく、可能なインデックスを使用して1つの値を読み取ります。

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.