将SQL转换为EF Linq

本文关键字:EF Linq 转换 SQL | 更新日期: 2023-09-27 18:24:05

我有以下查询:

SELECT COUNT(1)
FROM   Warehouse.WorkItems wi
WHERE  wi.TaskId = (SELECT TaskId
                    FROM   Warehouse.WorkItems
                    WHERE  WorkItemId = @WorkItemId)
  AND  wi.IsComplete = 0;

由于我们使用的是EF,我希望能够使用Linq功能来生成这个查询。(我知道我可以给它一个这样的字符串查询,但出于重构的原因,我想使用EF+Linq为我生成查询。)

我真的不需要知道查询的结果。我只需要知道是否有结果。(使用Any()将是完美的,但我无法获得它的编写代码。)

所以。。。基本上,我该如何将SQL查询写成LINQ查询?

编辑:表格结构

WorkItemId - int - Primary Key
TaskId - int - Foreign Key on Warehouse.Tasks
IsComplete - bool
JobId - int 
UserName - string
ReportName - string
ReportCriteria - string
ReportId - int - Foreign Key on Warehouse.Reports
CreatedTime - DateTime

将SQL转换为EF Linq

直接翻译可能类似于

var result = db.WorkItems.Any(wi =>
    !wi.IsComplete && wi.TaskId == db.WorkItems
        .Where(x => x.WorkItemId == workItemId)
        .Select(x => x.TaskId)
        .FirstOrDefault()));

考虑到当今现代数据库中SQL =(subquery)IN (subquery)EXISTS(subquery)的处理方式相同,您可以尝试使用

var result = db.WorkItems.Any(wi =>
    !wi.IsComplete && db.WorkItems.Any(x => x.WorkItemId == workItemId
        && x.TaskId == wi.TaskId));

事实证明,我只需要从不同的角度来处理这个问题。

我想出了大约三个不同Linq语法的解决方案:

全方法链:

var q1 = Warehouse.WorkItems
                  .Where(workItem => workItem.TaskId == (from wis in Warehouse.WorkItems
                                                           where wis.WorkItemId == workItemId
                                                           select wis.TaskId).First())
                  .Any(workItem => !workItem.IsComplete);

混合查询+方法链:

var q2 = Warehouse.WorkItems
                  .Where(workItem => workItem.TaskId == Warehouse.WorkItems
                                                                 .Where(wis => wis.WorkItemId == workItemId)
                                                                 .Select(wis => wis.TaskId)
                                                                 .First())
                  .Any(workItem => !workItem.IsComplete);

完整查询:

var q3 = (from wi in Warehouse.WorkItems
          where wi.TaskId == (from swi in Warehouse.WorkItems
                              where swi.WorkItemId == workItemId
                              select swi.TaskId).First()
          where !wi.IsComplete
          select 1).Any();

唯一的问题是它产生了一些真的劫持的SQL:

SELECT 
    (CASE 
        WHEN EXISTS(
            SELECT NULL AS [EMPTY]
            FROM [Warehouse].[WorkItems] AS [t0]
            WHERE (NOT ([t0].[IsComplete] = 1)) AND ([t0].[TaskId] = ((
                SELECT TOP (1) [t1].[TaskId]
                FROM [Warehouse].[WorkItems] AS [t1]
                WHERE [t1].[WorkItemId] = @p0
                )))
            ) THEN 1
        ELSE 0
     END) AS [value]

您可以像这样使用Any()函数:

var result = Warehouse.WorkItems.Any(x => x.WorkItemId != null);

简言之,你通过了你的条件,在这种情况下,就是检查你收藏的物品是否有ID

变量result将告诉您集合中的所有项目是否都有ID。

这里有一个有用的网页,可以帮助您开始使用LINQ:http://www.dotnetperls.com/linq

原始SQL中的子查询是无用的,因此不是Any()用法的好示例。它很简单:

SELECT COUNT(*)
FROM   Warehouse.WorkItems wi
WHERE  WorkItemId = @WorkItemId
  AND  wi.IsComplete = 0;

看起来,由于结果仅为0或1,猜测目的并基于如何编写Any(),它可能被写成:

SELECT  CASE WHEN EXISTS ( SELECT *
                           FROM   Warehouse.WorkItems wi
                           WHERE  WorkItemId = @WorkItemId AND
                                  wi.IsComplete = 0 ) THEN 1
             ELSE 0
        END;

那么使用Any():是有意义的

bool exists = db.WorkItems.Any( wi => wi.WorkItemId == workItemId & !wi.IsComplete );

编辑:对不起,我匆忙误读了原来的查询。以下是关于Linq用法的更新:

bool exists = db.WorkItems.Any( wi => 
   db.WorkItems
    .SingleOrDefault(wi.WorkItemId == workItemId).TaskId == wi.TaskId
  && !wi.IsComplete );

如果在原始SQL:中需要计数

var count = db.WorkItems.Count( wi => 
   db.WorkItems
    .SingleOrDefault(wi.WorkItemId == workItemId).TaskId == wi.TaskId
  && !wi.IsComplete );

再次对造成的混乱表示歉意。