【发布时间】:2019-10-13 04:34:48
【问题描述】:
我正在尝试加入产品和属性表并按产品 ID 对它们进行分组,以获取具有其属性的产品列表。所以我尝试了以下实体框架查询:
var productsWithAttributes = (from product in ctx.products
join attribute in ctx.attributes on product.id equals attribute.productId
select new
{
product = product,
a1 = attribute.a1,
a2 = attribute.a2,
a3 = attribute.a3,
a4 = attribute.a4
} into t
group t by t.product.id into g
select new
{
product = g.Select(p => p.product).FirstOrDefault(),
attributes = g.Select(r => new Attr()
{
a1 = r.a1,
a2 = r.a2,
a3 = r.a3,
a4 = r.a4
}).ToList()
}
).ToList();
但这花了大约 70 分钟,当我查看它生成的 SQL 查询时,我看到了数十个子查询和数十个连接。
然后我尝试在 sql server 上进行分组,并在应用程序服务器上投影到所需的结构中。这是 EF 代码:
var productsWithAttributes = (from product in ctx.products
join attribute in ctx.attributes on product.id equals attribute.productId
select new
{
product = product,
a1 = attribute.a1,
a2 = attribute.a2,
a3 = attribute.a3,
a4 = attribute.a4
} into t
group t by t.product.id
).ToList();
这大约需要 3 分钟。但是这个查询产生的 SQL 看起来仍然很复杂,有多个子查询和连接。我会期待以下内容:
select product.*, attribute.a1, attribute.a2, attribute.a3, attribute.a4
from product
join attribute on product.id = attribute.productId
group by product.id
然后我尝试了只加入而不分组:
var productsWithAttributes = (from product in ctx.products
join attribute in ctx.attributes on product.id equals attribute.productId
select new
{
product = product,
a1 = attribute.a1,
a2 = attribute.a2,
a3 = attribute.a3,
a4 = attribute.a4,
}
).ToList();
这花了 1.5 分钟,EF 生成的 SQL 代码符合预期。
简而言之,将分组添加到连接会创建一个复杂的 SQL 查询,它需要更长的时间,但在性能方面仍然可以接受。但是在这个分组之后添加最终的投影会产生一个非常复杂的 SQL 查询,它会花费大量的时间并且无法接受。
使用 EF 创建此查询的正确方法是什么?
【问题讨论】:
-
问题在于
select product.*, attribute.a1, attribute.a2, attribute.a3, attribute.a4与group by product.id的组合不是有效的SQL(至少对于大多数主要的关系数据库而言)。其次,所需的结果形状对于 SQL 来说是不自然的。但是,为什么您需要join和group by- 具有适当的实体导航属性,查询应该是简单的投影(select),具有相对简单的SQL 翻译?你的Product类中没有类似public ICollection<Attribute> Attributes { get; set; }的东西吗? -
@IvanStoev 不幸的是,数据库不包含关系。
-
我明白了。这是什么 EF - 6,Core(版本)?它是执行单个 SQL 查询还是 N + 1 个 SQL 查询?您能否分享查询中使用的类以及上述信息?目前的信息不足以给你一个好的建议。
-
@hakanviv 即使数据库不包含外键,您也可以定义导航属性。如前所述,这将使生活变得更加轻松。你可以做类似
product.Attributes的事情。同时,您应该想知道为什么没有 FK。考虑添加它们。
标签: c# entity-framework