Estoy usando ef core en mi proyecto de API de ASP Core. Tengo que encontrar el índice de orden más alto.
Ejemplo:
Tabla de datos: Id, ForeignId, OrderIndex
Así que estoy haciendo:
var highestOrderIndex = await _context .ExampleDbSet .Where(x => x.ForeignId == foreignId) .MaxAsync(x => x.OrderIndex); El problema es cuando el conjunto de base de datos de ejemplo contiene 0 elementos. Esto generará una excepción: la Sequence contains no element .
¿Hay una manera elegante de hacer esto? Porque no quiero obtener todos los elementos de la base de datos. Y debería ser asíncrono.
Gracias
Puede usar DefaultIfEmpty y Select antes de MaxAsync.
var highestOrderIndex = await _context .ExampleDbSet .Where(x => x.ForeignId == foreignId) .Select(x => x.OrderIndex) .DefaultIfEmpty() // default is 0 if OrderIndex is int or long // .DefaultIfEmpty(-1) // default is -1 .MaxAsync();Otra forma con un rendimiento un poco mejor que MaxAsync , si el valor predeterminado es el que desea obtener, si no hay resultados:
var highestOrderIndex = await _context.ExampleDbSet .Where(x => x.ForeignId == foreignId) .OrderByDescending(x => x.OrderIndex) .Select(x => x.OrderIndex) .FirstOrDefaultAsync(); TOP es más rápido que las funciones agregadas, mire el plan de ejecución en su servidor SQL.
Puede encontrar si existen registros y, si los hay, luego encontrar el máximo. Algo como esto:
var query = _context.ExampleDbSet .Where(x => x.ForeignId == foreignId); var itemsExist = await query.AnyAsync(); int maxOrderIndex = 0; if(itemsExist) { maxOrderIndex = await query.MaxAsync(x => x.OrderIndex); }Aquí no tendrá que recuperar todos los elementos de la base de datos, solo verifique si existe un registro, que es mucho más rápido y también puede mantener el método asíncrono.
Hacer un AnyAsync y luego un MaxAsync dará como resultado dos llamadas de base de datos separadas. Puede condensarlo en uno asegurándose de que la secuencia contenga un valor mínimo "predeterminado". Este es un truco útil en cualquier lugar donde use los métodos Linq Max/Min, no solo en el código de la base de datos:
context.ExampleDbSet .Where(w => w.ForeignId == foreignId) .Select(s => s.OrderIndex) .Concat(new[] { 0 }) .MaxAsync();En realidad, hay una forma bastante elegante (y más eficaz en comparación con la sugerida en la otra respuesta porque está ejecutando solo una consulta de base de datos) al utilizar el hecho de que los métodos agregados como Min , Max throw Sequence contains no element solo cuando se usa con no anulable sobrecargas, pero las sobrecargas anulables simplemente devuelven null en su lugar.
Entonces, todo lo que necesita es promover el tipo de propiedad que no acepta valores NULL al tipo que acepta valores NULL correspondiente. Por ejemplo, si el tipo OrderIndex es int , el único cambio en su consulta podría ser
.MaxAsync(x => (int?)x.OrderIndex); Tenga en cuenta que esto también cambiará el tipo de la variable highestOrderIndex a int? . Puede buscar null y reaccionar en consecuencia, o simplemente puede combinar la llamada de función agregada con ?? operador y proporcione algún valor predeterminado, por ejemplo
var highestOrderIndex = (await _context.ExampleDbSet .Where(x => x.ForeignId == foreignId) .MaxAsync(x => (int?)x.OrderIndex)) ?? -1; // or whatever "magic" number works for you