it-swarm.com.de

Maximaler Rückgabewert bei leerer Abfrage

Ich habe diese Abfrage:

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

Was wird in maxShoeSize sein, wenn Firma 8 überhaupt keine Arbeiter hat?

UPDATE:
Wie kann ich die Abfrage ändern, um 0 und keine Ausnahme zu erhalten?

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

Die Null in DefaultIfEmpty ist nicht erforderlich.

223
Ron K.

Ich weiß, dass dies eine alte Frage ist und die akzeptierte Antwort funktioniert, aber diese Frage hat meine Frage beantwortet, ob eine solche leere Menge zu einer Ausnahme oder einem default(int)-Ergebnis führt.

Die akzeptierte Antwort, obwohl sie funktioniert, ist IMHO nicht die ideale Lösung, die hier nicht gegeben wird. Daher gebe ich es in meiner eigenen Antwort zum Nutzen aller, die danach suchen.

Der ursprüngliche Code des OP war:

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

So würde ich es schreiben, um Ausnahmen zu verhindern und ein Standardergebnis anzugeben:

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

Dies führt dazu, dass der Rückgabetyp der Max-Funktion int? ist, wodurch das Ergebnis null zulässig ist und der ?? das Ergebnis null durch 0 ersetzt. 


EDIT
Um nur etwas aus den Kommentaren zu erklären, unterstützt Entity Framework derzeit nicht das as-Schlüsselwort. Daher können Sie es bei der Arbeit mit EF schreiben:

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

Da [TypeOfWorkers] ein langer Klassenname sein kann und langwierig zu schreiben ist, habe ich eine Erweiterungsmethode hinzugefügt, um zu helfen.

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

Dies behandelt nur int, das gleiche kann jedoch auch für long, double oder einen beliebigen anderen Werttyp erfolgen, den Sie benötigen. Die Verwendung dieser Erweiterungsmethode ist sehr einfach. Sie übergeben einfach Ihre Selector-Funktion und fügen optional einen Wert für null hinzu, der standardmäßig den Wert 0 hat. Die obigen Angaben könnten wie folgt umgeschrieben werden:

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

Hoffentlich hilft das den Leuten noch mehr.

45
CptRobby

Max () gibt in diesem Fall nichts zurück.

Dadurch wird InvalidOperationException ausgelöst, da die Quelle keine Elemente enthält.

24
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();
16
Danny Chen

Wenn dies Linq to SQL ist, benutze ich Any() nicht gern, da dies zu mehreren Abfragen an den SQL-Server führt.

Wenn ShoeSize kein nullfähiges Feld ist, funktioniert die Verwendung von nur .Max(..) ?? 0 nicht. Folgendes wird jedoch funktionieren:

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

Es ändert absolut nicht das ausgegebene SQL, aber es gibt 0 zurück, wenn die Sequenz leer ist, da Max() geändert wird, um einen int? anstelle einer int zurückzugeben.

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

(vorausgesetzt, dass ShoeSize vom Typ int ist)

Wenn Workers eine DbSet oder ObjectSet von Entity Framework ist, würde Ihre erste Abfrage eine InvalidOperationException auslösen, ohne sich über eine leere Sequenz zu beklagen, sondern darüber, dass der materialisierte Wert NULL nicht in eine int konvertiert werden kann.

2
Slauma

Hinweis: Die Abfrage mit DefaultIfEmpty() kann erheblich langsamer sein. In meinem Fall war das eine einfache Abfrage mit .DefaultIfEmpty(DateTime.Now.Date).

Ich war zu faul, um ein Profil zu erstellen, aber offensichtlich versuchte EF, alle Zeilen zu ermitteln und dann den Wert Max() zu nehmen.

Fazit: Manchmal ist die Behandlung von InvalidOperationException die bessere Wahl.

2
Andrey St

Max wirft System.InvalidOperationException "Sequenz enthält keine Elemente"

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

Sie können dies versuchen:

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

Sie können überprüfen, ob Arbeiter vorhanden sind, bevor Sie das Max () ausführen.

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

Sie können ein Ternary in .Max() verwenden, um das Prädikat zu behandeln und seinen Wert festzulegen.

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

Sie müssten die Workers-Auflistung als null/leer behandeln, wenn dies eine Möglichkeit ist, aber dies hängt von Ihrer Implementierung ab.

0
Jecoms