![](/img/trans.png)
[英]EF Core - DbContext disposed when query from multiple tables sequentially
[英]How to query EF Core dbcontext for specific attributes from navigation properties?
我试图获得最有效的查询来选择导航属性中的一些嵌套属性,以便 API 发送仅包含相关信息的响应。 到目前为止,我尝试了Include()
和ThenInclude()
方法以及这篇文章的答案。
然而,这两种方法都产生了类似的查询并从数据库中检索了相同的列。 唯一明显的区别是 Include 方法将不需要的列中的数据加载到实体对象属性中,而Select()
方法没有。 我正在使用图层模式,因此使用 null 类型对我来说不是一个选项,并且实体中的 nul 值不是问题,因为只有检索值最终加载到 dto 中,但仍然是查询效率问题遗迹。
我的问题是,是否有更好的方法从导航属性中查询单个列,如果没有,上述两种方法中的哪一种更好。
包括查询方法:
public async Task<IEnumerable<Orden>> GetDetailed()
{
return await _context.Ordenes
.Include(o => o.Detalles)
.ThenInclude(od => od.ProductosAlmacenados)
.Include(o => o.Detalles)
.ThenInclude(od => od.Tela)
.Include(o => o.Detalles)
.ThenInclude(od => od.Color)
.ToListAsync();
}
Select()
查询方法:
public async Task<IEnumerable<Orden>> GetDetailed()
{
var ordenes = await _context.Ordenes
.Select(o => new Orden
{
Id = o.Id,
Estatus = o.Estatus,
FechaRegistro = o.FechaRegistro,
FechaRequerida = o.FechaRequerida,
Detalles = o.Detalles.Select(d => new OrdenDetalles
{
Color = new Color
{
Nombre = d.Color.Nombre
},
Tela = new Tela
{
Nombre = d.Tela.Nombre,
},
Cantidad = d.Cantidad,
ProductosAlmacenados = d.ProductosAlmacenados
}).ToList()
}
).ToListAsync();
return ordenes;
}
由Select
生成的带有输出的查询:
SELECT `o`.`ID`, `o`.`Estatus`, `o`.`Fecha_Registro`, `o`.`Fecha_Requerida`, `t0`.`Nombre`, `t0`.`Nombre0`, `t0`.`Cantidad`, `t0`.`Color_ID`, `t0`.`Orden_ID`, `t0`.`Tela_ID`, `t0`.`ID`, `t0`.`ID0`, `t0`.`Almacen_ID`, `t0`.`OrdenDetalles_Color_ID`, `t0`.`OrdenDetalles_Orden_ID`, `t0`.`OrdenDetalles_Tela_ID`, `t0`.`Cantidad0`
FROM `orden` AS `o`
LEFT JOIN (
SELECT `c`.`Nombre`, `t`.`Nombre` AS `Nombre0`, `o0`.`Cantidad`, `o0`.`Color_ID`, `o0`.`Orden_ID`, `o0`.`Tela_ID`, `c`.`ID`, `t`.`ID` AS `ID0`, `a`.`Almacen_ID`, `a`.`OrdenDetalles_Color_ID`, `a`.`OrdenDetalles_Orden_ID`, `a`.`OrdenDetalles_Tela_ID`, `a`.`Cantidad` AS `Cantidad0`
FROM `ordendetalles` AS `o0`
INNER JOIN `color` AS `c` ON `o0`.`Color_ID` = `c`.`ID`
INNER JOIN `tela` AS `t` ON `o0`.`Tela_ID` = `t`.`ID`
LEFT JOIN `almacen_productos` AS `a` ON ((`o0`.`Color_ID` = `a`.`OrdenDetalles_Color_ID`) AND (`o0`.`Orden_ID` = `a`.`OrdenDetalles_Orden_ID`)) AND (`o0`.`Tela_ID` = `a`.`OrdenDetalles_Tela_ID`)
) AS `t0` ON `o`.`ID` = `t0`.`Orden_ID`
ORDER BY `o`.`ID`, `t0`.`Color_ID`, `t0`.`Orden_ID`, `t0`.`Tela_ID`, `t0`.`ID`, `t0`.`ID0`, `t0`.`Almacen_ID`, `t0`.`OrdenDetalles_Color_ID`, `t0`.`OrdenDetalles_Orden_ID`
Include()
生成的查询:
SELECT `o`.`ID`, `o`.`Estatus`, `o`.`Fecha_Registro`, `o`.`Fecha_Requerida`, `t0`.`Color_ID`, `t0`.`Orden_ID`, `t0`.`Tela_ID`, `t0`.`Cantidad`, `t0`.`ID`, `t0`.`ID0`, `t0`.`Almacen_ID`, `t0`.`OrdenDetalles_Color_ID`, `t0`.`OrdenDetalles_Orden_ID`, `t0`.`OrdenDetalles_Tela_ID`, `t0`.`Cantidad0`, `t0`.`Nombre`, `t0`.`Nombre0`
FROM `orden` AS `o`
LEFT JOIN (
SELECT `o0`.`Color_ID`, `o0`.`Orden_ID`, `o0`.`Tela_ID`, `o0`.`Cantidad`, `t`.`ID`, `c`.`ID` AS `ID0`, `a`.`Almacen_ID`, `a`.`OrdenDetalles_Color_ID`, `a`.`OrdenDetalles_Orden_ID`, `a`.`OrdenDetalles_Tela_ID`, `a`.`Cantidad` AS `Cantidad0`, `t`.`Nombre`, `c`.`Nombre` AS `Nombre0`
FROM `ordendetalles` AS `o0`
INNER JOIN `tela` AS `t` ON `o0`.`Tela_ID` = `t`.`ID`
INNER JOIN `color` AS `c` ON `o0`.`Color_ID` = `c`.`ID`
LEFT JOIN `almacen_productos` AS `a` ON ((`o0`.`Color_ID` = `a`.`OrdenDetalles_Color_ID`) AND (`o0`.`Orden_ID` = `a`.`OrdenDetalles_Orden_ID`)) AND (`o0`.`Tela_ID` = `a`.`OrdenDetalles_Tela_ID`)
) AS `t0` ON `o`.`ID` = `t0`.`Orden_ID`
ORDER BY `o`.`ID`, `t0`.`Color_ID`, `t0`.`Orden_ID`, `t0`.`Tela_ID`, `t0`.`ID`, `t0`.`ID0`, `t0`.`Almacen_ID`, `t0`.`OrdenDetalles_Color_ID`, `t0`.`OrdenDetalles_Orden_ID`
Orden
实体:
public partial class Orden
{
public Orden()
{
Detalles = new HashSet<OrdenDetalles>();
}
public int Id { get; set; }
public DateTime FechaRegistro { get; set; }
public DateTime FechaRequerida { get; set; }
public Estado Estatus { get; set; }
public virtual ICollection<OrdenDetalles> Detalles { get; set; }
}
OrdenDetalles
实体:
public partial class OrdenDetalles
{
public OrdenDetalles()
{
ProductosAlmacenados = new HashSet<ProductoAlmacenado>();
}
public int ColorId { get; set; }
public int OrdenId { get; set; }
public int TelaId { get; set; }
public int Cantidad { get; set; }
public virtual Color Color { get; set; }
public virtual Orden Orden { get; set; }
public virtual Tela Tela { get; set; }
public virtual ICollection<ProductoAlmacenado> ProductosAlmacenados { get; set; }
}
如果需要任何其他信息,请在评论中告诉我
使用 Select 进行投影通常是更好的方法,但是不要使用Select
来填充 Entity 类,而是填充仅包含您需要的详细信息的 DTO 或 ViewModel POCO 类。
您不想仅使用所需的详细信息部分填充 Entity 类的原因是因为这些实例不再代表完整的实体,它们是实体的部分外壳。 任何期望接收实体的方法都可以通过这些不完整的实体之一传递,例如默认值和#nulls。 使用 DTO 定义可以避免混淆将通过哪些数据。
跨实体图查询时,您可以将相关实体的详细信息展平为字段或不同的结构。 虽然 SQL 乍一看并没有那么不同,但投影通常会减少通过网络传输的数据量,并且还允许您针对高使用情况调整索引,从而显着提高性能。
因此,例如,您可以将 DTO 展平为:
var ordenes = await _context.Ordenes
.Select(o => new OrdenDto
{
Id = o.Id,
Estatus = o.Estatus,
FechaRegistro = o.FechaRegistro,
FechaRequerida = o.FechaRequerida,
Detalles = o.Detalles.Select(d => new OrdenDetallesDto
{
ColorNombre = d.Color.Nombre,
TelaNombre = d.Tela.Nombre,
Cantidad = d.Cantidad,
ProductosAlmacenados = d.ProductosAlmacenados
}).ToList()
}).ToListAsync();
return ordenes;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.