私はこのクエリを持っています:
int maxShoeSize = Workers
.Where(x => x.CompanyId == 8)
.Max(x => x.ShoeSize);
会社8に労働者がまったくいない場合、maxShoeSize
はどうなりますか?
更新:
クエリを変更して、例外ではなく0を取得するにはどうすればよいですか?
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty(0)
.Max();
DefaultIfEmpty
のゼロは必要ありません。
私はこれが古い質問であり、受け入れられた答えが機能することを知っていますが、この質問は、そのような空のセットが例外または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
のみを処理しますが、long
、double
、または他の必要な値の型についても同じことができます。この拡張メソッドの使用は非常に簡単です。セレクター関数を渡すだけで、オプションでnullに使用する値を含めることができます。デフォルトでは0です。したがって、上記のように書き換えることができます。
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);
うまくいけば、それがさらに人々を助けます。
Max() はその場合何も返しません。
ソースに要素が含まれていないため、 InvalidOperationException が発生します。
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty()
.Max();
これが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を返します。
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
.Max(x=>(int?)x.ShoeSize).GetValueOrDefault();
(ShoeSize
がint
型であると仮定)
Workers
がEntity FrameworkのDbSet
またはObjectSet
である場合、最初のクエリはInvalidOperationException
をスローしますが、空のシーケンスについては文句を言いませんが、実体化されたという文句を言います。値NULLはint
に変換できません。
注意:DefaultIfEmpty()
を使用したクエリは、かなり大きくなる可能性がありますslower。私の場合、それは.DefaultIfEmpty(DateTime.Now.Date)
を使用した単純なクエリでした。
私はそれをプロファイルするのが面倒でしたが、明らかにEFはすべての行を取得してからMax()
値を取得しようとしました。
結論:時々InvalidOperationException
を処理する方が良い選択かもしれません。
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;
}
これを試すことができます:
int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 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);
}
.Max()
内で3項を使用して、述部を処理し、その値を設定できます。
// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);
可能であれば、Workers
コレクションがnull /空であることを処理する必要がありますが、実装によって異なります。