Boş sorgu varsa maksimum dönüş değeri


175

Bu sorguyu var:

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

maxShoeSizeŞirket 8'in hiç çalışanı yoksa ne olacak ?

GÜNCELLEME:
İstisna değil, 0 almak için sorguyu nasıl değiştirebilirim?


Naor: LINQPad'i duydunuz mu?
Mitch Wheat

3
Neden 'İçinde ne olacak maxShoeSize?' Diye soracağını anlamıyorum. Eğer zaten denediyseniz.
jwg

@jwg: Cevabı bilip bilmediğini görmek istedim sanırım :) Sonunda istediğimi yapmanın daha iyi bir yolunu buldum ve demek istediğim bu.
Naor

@Hayır, bu bir tahmin oyunu değil. Ayrıca orijinal soruyu küçümseyeceğim. Cevabı biliyorsanız bize verin aksi halde tembel görünüyorsunuz. Hemen şimdi aynı soruyu sormak üzereydim ve istisna mesajı da dahil olmak üzere tüm bilgileri hazırlıyorum.
Juan Carlos Oropeza

Yanıtlar:


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

Sıfır girişi DefaultIfEmptygerekli değildir.


İşleri :) Ama benim kodda DefaultIfEmpty sıfır gerekli oldu.
Carlos Tenorio Pérez

1
Sorunun burada tam olarak cevaplanmayan ilk kısmı ile ilgili olarak: Resmi belgelere göre , boş dizinin jenerik tipi bir referans tipi ise, null alırsınız. Aksi takdirde, bu soruya göre , Max()boş bir dizinin çağrılması hatayla sonuçlanır.
Raimund Krämer

59

Bunun eski bir soru olduğunu ve kabul edilen cevabın işe yaradığını biliyorum, ancak bu soru böyle boş bir kümenin bir istisnaya mı yoksa default(int) .

Bununla birlikte, kabul edilen cevap işe yararken, burada verilmeyen ideal çözüm IMHO değildir. Bu yüzden onu arayan herkesin yararına kendi cevabımda veriyorum.

OP'nin orijinal kodu şuydu:

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

İstisnaları önlemek ve varsayılan bir sonuç sağlamak için nasıl yazacağım:

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

Bu, Maxişlevin dönüş türünün olmasına neden olur int?, bu da nullsonuca izin verir ve ardından sonucun ??yerini alır . null0


EDIT
Sadece yorumlardan bir şeyi açıklığa kavuşturmak için Entity Framework şu anda asanahtar kelimeyi desteklemediğinden, EF ile çalışırken yazmanın yolu:

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

Yana [TypeOfWorkers]uzun bir sınıf adı olması ve yazma sıkıcı olabilir, ben yardım etmek bir uzantısı yöntemi ekledik.

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

Bu yalnızca kolları intancak aynı için yapılabilir long, doublesen gerekmez, ya da başka bir değer türü. Bu genişletme yöntemini kullanmak çok basittir, sadece seçici işlevinizi iletirsiniz ve isteğe bağlı olarak null için kullanılacak bir değer eklersiniz, bu değer varsayılan olarak 0 olur. Böylece yukarıdaki gibi yeniden yazılabilir:

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

Umarım bu insanlara daha da fazla yardımcı olur.


3
Harika bir çözüm! Daha popüler DefaultIfEmptycevap sadece Maxbir değerlendirme yapmadığında iyi sonuç verir .
McGuireV10

@ McGuireV10 Evet, sonuçta Selectolduğu gibi bir toplu işlevi kullanacağımda genellikle orta adam olarak kullanmaktan hoşlanmam Max. Ben de düşünüyorum benim sadece null adlı döndürerek boş set ile anlaşma olur ise oluşturulan SQL, yani yaparak ekstra bir alt seçim sorgusu kullanabilirsiniz edeceğini (Henüz bu test etmedim). Olumlu oy ve geri bildirim için teşekkürler! ;)
CptRobby

Benzer şekilde McGuireV10 @, ShoeSizeilgili de aslında Uniformvarlık, ben kullanmak ister Workers.Where(x => x.CompanyId == 8).Select(x => x.Uniform).Max(x => x.ShoeSize)bunun yerine sadece bütün değerlendirmeyi tutacak, Maxişlevi: Workers.Where(x => x.CompanyId == 8).Max(x => x.Uniform.ShoeSize). EF'in sorguları nasıl verimli bir şekilde oluşturacağına karar vermede en büyük özgürlüğe sahip olmasını sağlamak için sorgularımda mümkün olduğunca az yöntem kullanmayı tercih ediyorum. ;-)
CptRobby

1
Bunu EntityFramework içinde çalıştıramadım. Herkes ışık tutabilir mi? (DefaultIfEmpty tekniğini kullanarak çalıştı).
Moe Sisko

1
Uzantı yönteminin genel bir sürümü: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;
relative_random


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

10

Bu SQL Linq ise, Any()SQL sunucusuna birden çok sorgu sonuçlandığı için kullanmak istemiyorum.

Eğer ShoeSizebir null alan değildir, o zaman sadece kullanarak .Max(..) ?? 0işe yaramaz ama şu olacak:

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

Kesinlikle yayılan SQL'i değiştirmez, ancak dizi boşsa 0 döndürür çünkü Max()bir int?yerine bir döndürmek için değiştirir int.


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

(bunun ShoeSizetür olduğunu varsayarsak)int )

Eğer Workersbir DbSetveya ObjectSetİdare Framework adresinin ilk sorgu atmak istiyorum InvalidOperationException, ama boş bir sıra şikayet ama değer NULL bir haline dönüştürülemez materialised şikayet değil int.


2

Max, System.InvalidOperationException "Sıra hiçbir öğe içermiyor"

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

Not: ile sorgu DefaultIfEmpty()önemli ölçüde yavaş olabilir . Benim durumumda ile basit bir sorgu oldu .DefaultIfEmpty(DateTime.Now.Date).

Profil vermek için çok tembeltim ama açıkçası EF tüm satırları alıp Max()değeri almaya çalıştı .

Sonuç: bazen kullanım InvalidOperationExceptiondaha iyi bir seçim olabilir.


0

Yüklemeyi .Max()işlemek ve değerini ayarlamak için içerideki bir üçlü kullanabilirsiniz ;

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

Bu Workersbir olasılık varsa koleksiyonun boş / boş olarak işlemesi gerekir , ancak uygulamanıza bağlıdır.


0

Bunu deneyebilirsiniz:

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

Bence Max bir int bekliyor ve bir null oluyor bu başarısız olacak; bu nedenle null birleştirme operatörü devreye girmeden önce bir hata oluştu.
d219

0

Max'i () yapmadan önce çalışan olup olmadığını kontrol edebilirsiniz.

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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.