2011-08-06 8 views
95

tengo esta consulta:valor máximo de devolución si consulta vacía

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

Qué habrá en maxShoeSize si la compañía no tiene 8 trabajadores en absoluto?

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

+0

Naor : ¿has oído hablar de LINQPad? –

+2

Cualquiera que vote a favor: describa por qué. – Naor

+5

no es mi voto a la baja, pero presumiblemente porque usted podría determinarlo fácilmente. –

Respuesta

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

El cero en DefaultIfEmpty no es necesario.

3

Max tirará System.InvalidOperationException "secuencia no contiene elementos"

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; 
} 
1
int maxShoeSize=Workers.Where(x=>x.CompanyId==8) 
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault(); 

(suponiendo que ShoeSize es de tipo int)

Si Workers es una DbSet o ObjectSet del marco de la entidad de su la consulta inicial arrojaría un InvalidOperationException, pero no se queja de una secuencia vacía, pero se queja de que el valor materializado NULL no se puede convertir int o un int.

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

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

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

Conclusión: a veces el manejo de InvalidOperationException podría ser la mejor opción.

28

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

La respuesta aceptada, sin embargo, mientras funciona, no es la solución ideal en mi humilde opinión, que no figura aquí. Por lo tanto, lo proporciono en mi propia respuesta para el beneficio de cualquier persona que lo esté buscando. código original

del OP fue:

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

Así es como lo escribiría para evitar 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 a ser int?, que permite el resultado null y luego el ?? reemplaza el resultado null con 0.

+1

¡Gran solución! La respuesta más popular de 'DefaultIfEmpty' solo funciona bien cuando' Max' no está haciendo una evaluación. – McGuireV10

+0

@ McGuireV10 Sí, normalmente no me gusta usar 'Seleccionar' como intermediario cuando voy a utilizar una función agregada como' Máx' en el resultado. También creo que (todavía no lo he probado) que el SQL generado usaría una consulta de subselección extra al hacer eso, mientras que el mío solo trataría con un conjunto vacío al devolver nulo. Gracias por el voto positivo y comentarios! ;) – CptRobby

+0

@ McGuireV10 Del mismo modo, si el 'ShoeSize' estaba realmente en una entidad' Uniform' relacionada, no usaría 'Workers.Where (x => x.CompanyId == 8) .Seleccione (x => x.Uniform) .Max (x => x.ShoeSize) ', en su lugar, simplemente mantendría toda la evaluación en la función' Max': 'Workers.Where (x => x.CompanyId == 8) .Max (x => x.Uniform.ShoeSize)'. Prefiero usar la menor cantidad posible de métodos en mis consultas para permitir que EF tenga la mayor libertad para decidir cómo construir consultas de manera eficiente. ;-) – CptRobby

0

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); 

Usted tendría que manejar la colección Workers siendo nula/vacía si eso es una posibilidad, pero que dependerá de su aplicación.

0

Puede probar esto:

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

se puede comprobar si hay trabajadores antes de hacer el máximo().

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

Si esto es LINQ a SQL, no me gusta utilizar Any() porque da lugar a varias consultas al servidor SQL.

Si ShoeSize no es un campo anulable, a continuación, utilizando sólo el .Max(..) ?? 0 no va a funcionar, pero lo siguiente:

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

Es absolutamente no cambia el SQL emitido, pero no devuelven 0 si la secuencia es ¿vacío porque cambia el Max() para devolver un int? en lugar de un int.

Cuestiones relacionadas