Valor máximo devuelto si consulta vacía


Tengo esta pregunta:

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

¿Qué habrá en maxShoeSize si la empresa 8 no tiene trabajadores?

ACTUALIZACIÓN:
¿Cómo puedo cambiar la consulta para obtener 0 y no una excepción?

Author: DdW, 2011-08-06

11 answers

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

El cero en DefaultIfEmpty no es necesario.

 200
Author: Ron K.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-27 11:44:29

Sé que esta es una pregunta antigua y la respuesta aceptada funciona, pero esta pregunta respondió a mi pregunta sobre si un conjunto vacío de este tipo resultaría en una excepción o un resultado default(int).

La respuesta aceptada, sin embargo, si bien funciona, no es la solución ideal en mi humilde opinión, que no se da aquí. Por lo tanto, lo estoy proporcionando en mi propia respuesta para el beneficio de cualquiera que lo esté buscando.

El código original de la OP era:

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

Así es como lo escribiría para prevenir excepciones y proporcionar un resultado predeterminado:

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

Esto hace que el tipo de retorno de la función Max sea int?, lo que permite el resultado null y luego el ?? reemplaza el resultado null con 0.


EDITAR
Solo para aclarar algo de los comentarios, Entity Framework actualmente no admite la palabra clave as, por lo que la forma de escribirla cuando se trabaja con EF sería:

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

Dado que el [TypeOfWorkers] podría ser un nombre de clase largo y es tedioso para escribir, he añadido un método de extensión para ayudar.

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

Esto solo maneja int, pero lo mismo podría hacerse para long, double, o cualquier otro tipo de valor que necesite. Usar este método de extensión es muy simple, simplemente pasa tu función de selector y opcionalmente incluye un valor para ser usado para null, que por defecto es 0. Así que lo anterior podría ser reescrito de la siguiente manera:

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

Esperemos que eso ayude a la gente aún más.

 37
Author: CptRobby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-25 13:26:26

Max () no devolverá nada en ese caso.

Levantará InvalidOperationException ya que la fuente no contiene elementos.

 19
Author: Frédéric Hamidi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-06 12:16:39
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();
 16
Author: Danny Chen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-06 13:28:05

Max lanzará el Sistema.InvalidOperationException "Sequence contains no elements"

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;
}
 3
Author: Johan Tidén,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-06 12:33:22
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault();

(suponiendo que ShoeSize es de tipo int)

Si Workers es un DbSet o ObjectSet de Entity Framework, su consulta inicial arrojaría un InvalidOperationException, pero no se quejaría de una secuencia vacía, sino que se quejaría de que el valor materializado NULL no se puede convertir en un int.

 1
Author: Slauma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-06 12:46:18

NB: la consulta con DefaultIfEmpty()puede ser significativamente más lenta. En mi caso fue una simple consulta con .DefaultIfEmpty(DateTime.Now.Date).

Yo era demasiado perezoso para perfilar. Pero, obviamente, EF intentó obtener todas las filas y luego tomar el valor Max ().

Conclusión: a veces manejar InvalidOperationException podría ser la mejor opción.

 1
Author: Andrey St,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-10 10:40:00

Puedes probar esto:

int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;
 1
Author: Carlos Toledo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-07 21:39:08

Puede usar un ternario dentro de .Max() para manejar el predicado y establecer su valor;

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

Tendría que manejar la colección Workers siendo null/empty si esa es una posibilidad, pero dependería de su implementación.

 0
Author: Jecoms,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-07 20:37:59

Puedes comprobar si hay algún trabajador antes de hacer el 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
Author: Reverend Sfinks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-03 11:00:38

Si esto es Linq a SQL, no me gusta usar Any() porque resulta en múltiples consultas a SQL server.

Si ShoeSize no es un campo nullable, entonces usar solo el .Max(..) ?? 0 no funcionará, pero lo siguiente lo hará:

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

No cambia absolutamente el SQL emitido, pero devuelve 0 si la secuencia está vacía porque cambia el Max() para devolver un int? en lugar de un int.

 0
Author: abkonsta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-13 22:02:50