[英]Linq to Entities many to many selection: How to force the generation of a JOIN instead of a subselect clause?
首先使用EF DB,我有两个具有多对多关系的实体(供应商,产品)。 实体框架不为关联表(SupplierProduct)创建实体,因为关联表仅包含强实体的主键。
我一直在向所有不提供给定产品的供应商提供以下查询:
var q1 = context.Suppliers.Where(s=>!s.Products.Any(p=>p.Id == 1));
生成的SQL使用类似于此的EXISTS依赖子查询:
SELECT *
FROM Suppliers s
WHERE NOT EXISTS
(SELECT 1
FROM SupplierProduct sp WHERE sp.SupplierId = s.Id && sp.ProductId = 1)
是否可以使用Linq to Entities方法语法生成在关联表上使用连接的查询?
即:
SELECT DISTINCT s.*
FROM SupplierProduct sp
JOIN Supplier s ON s.Id = sp.SupplierId;
WHERE sp.ProductId != 1
更新
正如JoeEnos所指出的,我上面的查询并没有做同样的事情。 NOT EXISTS子查询可能是最好的方法。 如果我试图让所有的供应商是谁做供应的产品? 我会将我的linq更改为实体查询稍微:
var q1 = context.Suppliers.Where(s => s.Products.Any(p=>p.Id == 1));
并且生成的SQL将是:
SELECT *
FROM Suppliers s
WHERE EXISTS
(SELECT 1
FROM SupplierProduct sp WHERE sp.SupplierId = s.Id && sp.ProductId = 1)
哪个好,我得到了我想要的结果。 但是,如果我在这种情况下编写SQL,我通常会这样做:
SELECT s.*
FROM SupplierProduct sp
JOIN Supplier s ON s.Id = sp.SupplierId;
WHERE sp.ProductId = 1
可以将我的linq to entities查询更改为生成上述SQL吗?
要生成使用连接而不是EXISTS的SQL,当根据其与另一个实体的m:n关联选择实体时,可以使用SelectMany() 。 例如:
var q1 = context.Suppliers.Where(s => s.Products.Any(p=>p.Id == 1));
可以改写为:
var q1 = context.Products.Where(p => p.Id == 1).SelectMany(p => p.Suppliers);
你的两个查询做了很多不同的事情。 您的Any
/ EXISTS
查询会获得根本没有产品1的供应商。 您的JOIN
查询将获得所有非1的产品的供应商,无论他们是否也有产品1。
我认为你只需要一个JOIN
和WHERE
就可以做你正在寻找的东西 - 你可以使用IN
子句来做,但我认为EXISTS
查询是查找数据的最正确方法。
在任何情况下,关于实体框架的一个奇妙的事情是你不必担心生成什么 - 只要LINQ语句没问题,那么它将找到编写查询的最佳方式,你应该永远不要去看它。 当你进行分页和其他类似的事情时,尤其如此,LINQ很简单,但生成的SQL非常难看。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.