将嵌套查询SQL转换为EF

时间:2015-03-12 21:40:12

标签: entity-framework

我有这个表结构:

enter image description here

经典的多对多关系。我希望获得属于我所提供的少量产品的所有产品的订单。显示完全符合我想要的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();

2 个答案:

答案 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
  • 取代
  • LINQ强制执行加入条件的方式,因此我必须将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适用于任何实现IEnumerableIQueryable的集合,包括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'))
    )