空のクエリの場合の最大戻り値


175

私はこのクエリを持っています:

int maxShoeSize = Workers
    .Where(x => x.CompanyId == 8)
    .Max(x => x.ShoeSize);

maxShoeSize会社8に労働者がまったくいない場合はどうなりますか?

更新:
例外ではなく0を取得するためにクエリを変更するにはどうすればよいですか?


Naor:LINQPadをご存知ですか?
Mitch Wheat

3
なんで「なにが入るのmaxShoeSize?」と聞かれるのかわからない。あなたがすでにそれを試していたなら。
jwg 2013年

@jwg:私はあなたが答えを知っているかどうかを見たかったのだと思います:)最終的に私は私が尋ねたことを行うためのより良い方法を得ました、そしてこれは私が意味したものです。
Naor 2013年

@Naor、これは推測ゲームではありません。元の質問にも反対票を投じます。あなたが答えを知っているなら私たちにそれを与えてください、さもなければあなたは怠惰に見えます。ちょうど今私は同じ質問をしようとしていて、例外メッセージを含むすべての情報を準備します。
ファンカルロス

回答:


298
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                         .Select(x => x.ShoeSize)
                         .DefaultIfEmpty(0)
                         .Max();

ゼロインDefaultIfEmptyは必要ありません。


動作:)しかし、私のコードではDefaultIfEmptyのゼロが必要でした。
Carlos TenorioPérez2018

1
ここでは完全に回答されていない質問の最初の部分について:公式のドキュメントによると、空のシーケンスのジェネリック型が参照型である場合、nullを取得します。そうでない場合、この質問によればMax()、空のシーケンスを呼び出すとエラーが発生します。
RaimundKrämer19年1

59

私はこれが古い質問であり、受け入れられた回答が機能することを知っていますが、この質問は、そのような空のセットが例外になるか結果になるかについての私の質問に答えましたdefault(int)

ただし、受け入れられた答えは機能しますが、ここでは示していないIMHOの理想的なソリューションではありません。したがって、私はそれを探している人のために自分の答えでそれを提供しています。

OPの元のコードは次のとおりです。

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);

これは私が例外を防ぎ、デフォルトの結果を提供するためにそれを書く方法です:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;

これにより、Max関数の戻り値の型がint?になり、null結果が許可され、結果がに??置き換えnullられ0ます。


編集
コメントから何かを明確にするために、Entity Frameworkは現在asキーワードをサポートしていないため、EFで作業するときにキーワードを記述する方法は次のようになります。

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;

[TypeOfWorkers]はクラス名が長く、書くのが面倒なので、手助けする拡張メソッドを追加しました。

public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
    return source.Max(selector) ?? nullValue;
}

これだけのハンドルintが、同じことがのために行うことができるlongdoubleあなたが必要とする、または任意の他の値型。この拡張メソッドの使用は非常に簡単です。セレクター関数を渡すだけで、オプションでnullに使用する値を含めることができます。デフォルトは0です。したがって、上記のように書き直すことができます。

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);

うまくいけば、それが人々をさらに助けます。


3
素晴らしい解決策!より一般的なDefaultIfEmpty答えMaxは、が評価を行っていない場合にのみ機能します。
McGuireV10 2016年

@ McGuireV10ええ、私は通常、結果のSelectようMaxに集計関数を使用するつもりのときに、仲介者として使用するのは好きではありません。また、私は考えて鉱山はちょうどヌルを返すことで、空のセットに対処するだろうが生成されたSQLは、そうすることによって、余分な副選択クエリを使用することを(私はまだこれをテストしていません)。賛成票とフィードバックをありがとう!;)
CptRobby 2016年

@ McGuireV10同様に、ShoeSizeが実際に関連するUniformエンティティにある場合、は使用せずWorkers.Where(x => x.CompanyId == 8).Select(x => x.Uniform).Max(x => x.ShoeSize)、代わりにMax関数全体の評価を保持しますWorkers.Where(x => x.CompanyId == 8).Max(x => x.Uniform.ShoeSize)。クエリを効率的に構築する方法をEFが自由に決定できるように、クエリではできるだけ少ない方法を使用することを好みます。;-)
CptRobby 2016年

1
これをEntityFrameworkで機能させることができませんでした。誰かが光を当てることはできますか?(DefaultIfEmptyテクニックを使用するとうまくいきました)。
Moe Sisko

1
拡張メソッドのジェネリックバージョン:public static TResult MaxOrDefault<TElement, TResult>(this IQueryable<TElement> items, Expression<Func<TElement, TResult>> selector, TResult defaultValue = default) where TResult : struct => items.Select(selector).Max(item => (TResult?)item) ?? defaultValue;
比較的



10

これがLinq to SQLの場合Any()、SQLサーバーへの複数のクエリが発生するため、使用したくありません。

ShoeSizeがnull許容フィールドでない場合は、だけを使用して.Max(..) ?? 0も機能しませんが、次のようになります。

int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;

生成されたSQLは絶対に変更されませんが、がMax()int?代わりにを返すように変更されるため、シーケンスが空の場合は0 を返しintます。


4
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault();

(それShoeSizeがタイプであると仮定int

WorkersがEntity Frameworkから、DbSetまたはObjectSetEntity Frameworkからの場合、最初のクエリはをスローしますがInvalidOperationException、空のシーケンスについては不平を言いませんが、実体化された値NULLはに変換できないと不平を言いますint


2

MaxはSystem.InvalidOperationException "シーケンスに要素が含まれていません"をスローします

class Program
{
    static void Main(string[] args)
    {
        List<MyClass> list = new List<MyClass>();

        list.Add(new MyClass() { Value = 2 });

        IEnumerable<MyClass> iterator = list.Where(x => x.Value == 3); // empty iterator.

        int max = iterator.Max(x => x.Value); // throws System.InvalidOperationException
    }
}

class MyClass
{
    public int Value;
}

2

注:を使用したクエリはDefaultIfEmpty()大幅に遅くなる可能性があります。私の場合、それはを使用した単純なクエリでした.DefaultIfEmpty(DateTime.Now.Date)

私はそれをプロファイリングするのが面倒でしたが、EFはすべての行を取得してからMax()値を取得しようとしました。

結論:場合InvalidOperationExceptionによっては、処理の方が適していることがあります。


0

内で三項を使用し.Max()て述語を処理し、その値を設定できます。

// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);

Workersそれが可能であれば、null /空のコレクションを処理する必要がありますが、実装によって異なります。


0

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

int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;

Maxはintを期待していて、nullを取得しているので、これは失敗すると思います。したがって、null結合演算子が有効になる前に、エラーがすでに発生しています。
d219

0

Max()を実行する前に、ワーカーがあるかどうかを確認できます。

private int FindMaxShoeSize(IList<MyClass> workers) {
   var workersInCompany = workers.Where(x => x.CompanyId == 8);
   if(!workersInCompany.Any()) { return 0; }
   return workersInCompany.Max(x => x.ShoeSize);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.