web-dev-qa-db-ja.com

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

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

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

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

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

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

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

248
Ron K.

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

しかし、受け入れられた答えは機能しますが、私見では理想的な解決策ではありません。したがって、私はそれを探している人の利益のために自分の答えでそれを提供しています。

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


[〜#〜] edit [〜#〜]
コメントから何かを明確にするために、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);

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

50
CptRobby

Max() はその場合何も返しません。

ソースに要素が含まれていないため、 InvalidOperationException が発生します。

28
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();
17
Cheng Chen

これがLinq to SQLの場合、Any()を使用したくないのは、SQLサーバーへの複数のクエリが発生するためです。

ShoeSizeがNULL入力可能フィールドでない場合、.Max(..) ?? 0のみを使用しても機能しませんが、次のようになります。

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

出力されたSQLは絶対に変更されませんが、intではなく_int?_を返すようにMax()を変更するため、シーケンスが空の場合は0を返します。

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

ShoeSizeint型であると仮定)

WorkersがEntity FrameworkのDbSetまたはObjectSetである場合、最初のクエリはInvalidOperationExceptionをスローしますが、空のシーケンスについては文句を言いませんが、実体化されたという文句を言います。値NULLはintに変換できません。

3
Slauma

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

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

結論:時々InvalidOperationExceptionを処理する方が良い選択かもしれません。

2
Andrey St

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
Johan Tidén

これを試すことができます:

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

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);
}
0
Reverend Sfinks

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

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

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

0
Jecoms