J'ai cette requête:
int maxShoeSize = Workers
.Where(x => x.CompanyId == 8)
.Max(x => x.ShoeSize);
Que sera-t-il dans maxShoeSize
si la société 8 n’a aucun travailleur?
METTRE À JOUR:
Comment puis-je changer la requête afin d’obtenir 0 et pas une exception?
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty(0)
.Max();
Le zéro dans DefaultIfEmpty
n'est pas nécessaire.
Je sais que cette question est ancienne et que la réponse acceptée fonctionne, mais cette question répondait à ma question de savoir si un tel ensemble vide entraînerait une exception ou un résultat default(int)
.
La réponse acceptée cependant, bien que cela fonctionne, n’est pas la solution idéale IMHO, qui n’est pas donnée ici. Ainsi, je le fournis dans ma propre réponse au profit de tous ceux qui le recherchent.
Le code d'origine du PO était le suivant:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);
Voici comment je l'écrirais pour éviter les exceptions et fournir un résultat par défaut:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;
Ainsi, le type de retour de la fonction Max
est int?
, ce qui permet d'obtenir le résultat null
, puis le ??
remplace le résultat null
par 0
.
MODIFIER
Juste pour clarifier quelque chose à partir des commentaires, Entity Framework ne prend pas en charge le mot clé as
.
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;
Puisque le [TypeOfWorkers]
pourrait être un nom de classe long et qu'il est fastidieux à écrire, j'ai ajouté une méthode d'extension pour vous aider.
public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
return source.Max(selector) ?? nullValue;
}
Ceci ne traite que int
, mais la même chose peut être faite pour long
, double
ou tout autre type de valeur dont vous avez besoin. L'utilisation de cette méthode d'extension est très simple, il vous suffit de passer votre fonction de sélecteur et d'inclure éventuellement une valeur à utiliser pour null, dont la valeur par défaut est 0. Donc, la procédure ci-dessus pourrait être réécrite de la manière suivante:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);
Espérons que cela aide les gens encore plus.
Max () ne retournera rien dans ce cas.
Il déclenchera InvalidOperationException puisque la source ne contient aucun élément.
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty()
.Max();
S'il s'agit de Linq to SQL, je n'aime pas utiliser Any()
car il en résulte plusieurs requêtes sur le serveur SQL.
Si ShoeSize
n'est pas un champ nullable, utiliser uniquement la fonction .Max(..) ?? 0
ne fonctionnera pas, mais les suivants:
int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;
Cela ne change absolument pas le code SQL émis, mais renvoie 0 si la séquence est vide, car la fonction Max()
est remplacée par un int?
au lieu d'une int
.
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
.Max(x=>(int?)x.ShoeSize).GetValueOrDefault();
(en supposant que ShoeSize
est de type int
)
Si Workers
est une DbSet
ou ObjectSet
de Entity Framework, votre requête initiale lancera une InvalidOperationException
, mais ne se plaindra pas d'une séquence vide mais se plaindra que la valeur matérialisée NULL ne peut pas être convertie en int
.
NB: la requête avec DefaultIfEmpty()
peut être significativement plus lente . Dans mon cas, il s’agissait d’une requête simple avec .DefaultIfEmpty(DateTime.Now.Date)
.
J'étais trop paresseux pour le profiler mais EF a évidemment essayé d'obtenir toutes les lignes, puis de prendre la valeur Max()
.
Conclusion: parfois manipuler InvalidOperationException
pourrait être le meilleur choix.
Max lancera System.InvalidOperationException "La séquence ne contient aucun élément"
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;
}
Vous pouvez essayer ceci:
int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;
Vous pouvez vérifier s'il y a des ouvriers avant de faire le 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);
}
Vous pouvez utiliser un élément ternaire dans .Max()
pour gérer le prédicat et définir sa valeur;
// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);
Vous devez gérer la collection Workers
comme nulle/vide si c'est une possibilité, mais cela dépend de votre implémentation.