Tengo una pregunta sobre Entity Framework Core y el uso de LINQ. Me gustaría obtener los otros detalles de la tabla mientras accedo a la tabla Clients . Puedo obtenerlos usando el siguiente código. Hay un total de alrededor de 10 mesas a las que debo unirme, en este caso, ¿el siguiente enfoque es bueno o cualquier otro enfoque mejor? ClientId es la clave externa para todas las tablas.
En realidad, estoy recibiendo una advertencia como la siguiente
[09:34:33 Advertencia] Microsoft.EntityFrameworkCore.Query Compilación de una consulta que carga colecciones relacionadas para más de una colección de navegación, ya sea a través de 'Incluir' o mediante proyección, pero no se ha configurado 'QuerySplittingBehavior'. De forma predeterminada, Entity Framework usará 'QuerySplittingBehavior.SingleQuery', lo que puede resultar en un rendimiento de consulta lento. Consulte https://go.microsoft.com/fwlink/?linkid=2134277 para obtener más información. Para identificar la consulta que desencadena esta advertencia, llame a 'ConfigureWarnings(w => w.Throw(RelationalEventId.MultipleCollectionIncludeWarning))'
Código:
var client = await _context.Clients .Include(x => x.Address) .Include(x => x.Properties) .Include(x => x.ClientDetails) ------------------- ------------------- ------------------- ------------------- .Where(x => x.Enabled == activeOnly && x.Id == Id).FirstOrDefaultAsync();En realidad, cuando usa la carga ansiosa (usando include() ), usa la combinación izquierda (todas las consultas necesarias en una consulta) para obtener datos. Es el comportamiento predeterminado de ef en ef 5. Puede configurar AsSplitQuery() en su consulta para dividir todo incluido en consultas separadas. me gusta:
var client = await _context.Clients .Include(x => x.Address) .Include(x => x.Properties) .Include(x => x.ClientDetails) ------------------- ------------------- ------------------- ------------------- .Where(x =>x.Id == Id).AsSplitQuery().FirstOrDefaultAsync() Este enfoque necesita más conexión a la base de datos, pero no es nada realmente importante. y para la recomendación final, aconsejo usar AsNoTracking() para consultas de alto rendimiento.
Tengo 3 enfoques diferentes según la versión de EF Core que esté usando
EF Core 5: como algunos mencionaron en respuestas anteriores, hay una nueva llamada que simplemente dividirá la consulta en subconsultas más pequeñas y mapeará todas las relaciones al final.
/*rest of the query here*/.AsSplitQuery();Si no puede simplemente migrar su versión de EF, aún puede dividir la consulta manualmente
var client = await _context.Clients.FirstOrDefaultAsync(t => t.Enabled /*other conditions*/); var Address = await _context.Addresses.FirstOrDefaultAsync(t => t.ClientId == client.Id); /// Because they are tracked EF's entitytracker can under the hood /// map the sub queries to their correct relations /// in this case you should not use .AsNoTracking() /// unless you would want to stitch relations together yourself Otra alternativa es escribir su consulta como una instrucción Select . Esto mejora enormemente el rendimiento, pero es un poco más complicado de construir.
var clientResult = await _context.Clients.Where(x => x.Id == id).Select(x => new { client = x, x.Address, Properties = x.Properties.Select(property => new { property.Name /*sub query for one to many related*/ }).ToList(), x.ClientDetails }).ToListAsync(); no se necesitan muchas inclusiones para crear una explosión cartesiana
puede leer más sobre el problema en cuestión en este artículo aquí explosión cartesiana en EF Core
y el enlace de referencia para optimizar el rendimiento a través de EF Core se puede encontrar aquí Maximizar el rendimiento de consultas de Entity Framework Core