我有这个表结构:
经典的多对多关系。我希望获得属于我所提供的少量产品的所有产品的订单。显示完全符合我想要的SQL可能更容易:
select o.*
from [Order] o join Product p2 on o.FKCatalogNumber=p2.CatalogNumber
where p2.FKCategoryId IN
(select c.Id
from Category c join Product p1 on p1.FKCategoryId=c.Id
where p1.CatalogNumber in ('0001', '0002')
这个例子给了我所有属于目录#0001和0002所在类别的订单。
但我无法围绕此查询的等效EF语法。我很尴尬地说我花了半天时间。我敢打赌那里的人很容易。
我想出了这个,但它不起作用(可能甚至没有关闭):
string[] catNumbers = {"0001", "0002"};
var orders = ctx.Categories
.SelectMany(c => c.Products, (c, p) => new {c, p})
.Where(@t => catNumbers.Contains(@t.p.CatalogNumber))
.Select(@t => @t.p.Orders)
.ToList();
答案 0 :(得分:2)
您可以在LINQ中使用查询语法(看起来与SQL非常相似),因此如果您对SQL更熟悉,那么您可能更喜欢这样编写查询:
string[] catNumbers = {"0001", "0002"};
var orders = from o in ctx.Orders
join p2 in ctx.Products on o.FKCatalogNumber equals p2.CatalogNumber
where
(
from c in ctx.Categories
join p1 in ctx.Products on c.ID equals p1.FKCategoryId
where catNumbers.Contains(p1.CatalogNumber)
select c.ID
).Contains(p2.FKCategoryId)
select o;
正如您所看到的,实际上只是您的SQL查询稍微重新排列,但它编译为C#。
请注意:
[Order] o
语法被o in ctx.Orders
on o.FKCatalogNumber=p2.CatalogNumber
翻转为on o.FKCatalogNumber equals p2.CatalogNumber
where p2.FKCategoryId IN (...)
,等效的c#是(...).Contains(p2.FKCategoryId)
select
是最后一个,而不是第一个但这些是唯一的重大变化。否则,它就像SQL一样编写。
我还提请你注意这个评论的区别:
此查询的等效EF语法
此处的语法并非特定于EF,而只是LINQ - L anguage In tegrated Q uerying。它有两种形式:查询语法(有时称为声明性)和方法语法(有时称为流畅)。 LINQ适用于任何实现IEnumerable
或IQueryable
的集合,包括EF的DbSet
。
有关不同查询方式的更多信息,this MSDN page是一个不错的起点。还有this handy reference table显示每个方法语法运算符的等效查询语法(如果适用)。
答案 1 :(得分:1)
您仍然可以在EF中嵌套查询。以下看起来对我有用:
string[] catNumbers = {"0001", "0002"};
var orders = ctx.Orders
.Where(o => ctx.Products
.Where(p => catNumbers.Contains(p.CatalogNumber))
.Select(p => p.CategoryId)
.Contains(o.Product.CategoryId)
);
这会生成以下SQL:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[CatalogNumber] AS [CatalogNumber]
FROM [dbo].[Orders] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Products] AS [Extent2]
INNER JOIN [dbo].[Products] AS [Extent3] ON [Extent2].[CategoryId] = [Extent3].[CategoryId]
WHERE ([Extent1].[CatalogNumber] = [Extent3].[CatalogNumber]) AND ([Extent2].[CatalogNumber] IN (N'0001', N'0002'))
)