LinqToSQL In Clause

时间:2011-01-26 20:17:54

标签: c# sql-server-2005 linq-to-sql

我正在尝试使用LinqToSQL生成一个可能包含很多项的IN子句。我的原始代码类似于:

context.Employees.Where(p => EmployeeIDs.Contains(p.EmployeeID));

最终生成一个in子句,每个employee id作为SQL参数。问题是如果你超过2100参数,则抛出异常。我通过执行多个查询并组合结果,在我的应用程序的其他地方解决了这个问题。这在简单的情况下工作正常,但我现在正在做一些更复杂的事情,我不认为这是最好的解决方案。

无论如何,Contains会产生类似

的内容
EmployeesID IN (@p0, @p1, @p2)

但有没有办法说服它这样做?

EmployeesID IN (23, 582, 3948)

我开始沿着使用动态查询示例的路径,但后来意识到它似乎只是编写动态linq代码,而不是动态sql。然后我找到了ExecuteQuery,但我不想手动构建我的整个查询字符串,只是我想要的查询的特定部分。

更具体地说,我想要像:

context.Employees
    .Where(p => p.Active == true)
    .Where("EmployeeID IN (23, 582, 3948)");

或者最好(如果这会在不使用参数的情况下生成IN):

context.Employees
    .Where(p => p.Active == true)
    .Where(p => p.In("EmployeeID", EmployeeIDs));

有什么办法吗?感谢。

2 个答案:

答案 0 :(得分:0)

您是否可以定义一个查询,该查询将根据其他查询返回所需的员工ID?如果是这样,您可以使用嵌套查询定义搜索:

var employeeIds = from x in context.EitherEmployeesOrSomeOtherRecords
   where x.SomeConditionIsTrue
   select x.EmployeeID; //not yet evaluated; employeeIds is an IQueryable

var employees = from e in context.Employees
   where employeeIds.Contains(x.EmployeeID)
   select e;

这个LINQ查询将被Linq2SQL消化为单个SQL语句,使用EXISTS子句来检查employeeIds子查询的SQL等价物。

至于强制Linq2SQL将代码中的值指定为文字,我认为你不能,但我可能错了。

编辑:那么,如果您确定如何更智能地构建查询,那该怎么办?比如,如果您有一个“全选”按钮或复选框,您可以使用它来制作一个更简单的查询,“拉出本来为列表选择的所有员工”:

var employees = from e in context.Employees
   where TheSameConditionThatCausedItToBeInTheList == true
   select e;

如果用户选择了全部,然后取消选择了一些,则可以检测到(更多选择而不是),而是拉出“所有员工除了X,Y和Z”:

var notChecked = uiList.Items.Except(uiList.SelectedItems).Select(x=>x.EmployeeID)

var employees = from e in context.Employees
   where !notChecked.Contains(e.EmployeeID)
   select e;

如果你有超过4200名员工,以上并不总是有效(你可以选择超过2100但未选择超过2100,所以它会爆炸),但我也无法想象一个列表4200项不允许您根据其他指标(即部门)进行选择,允许查询“拉出X,Y和Z部门的所有员工,以及员工A,B和C”:

var metaSelection = departmentList.SelectedItems.Select(x=>x.DepartmentID);

var exceptions = uiList.SelectedItems.Where(x=>!metaSelection.Contains(x.DepartmentID))
                       .Select(x=>x.EmployeeID);

var employees = from e in context.Employees
    where metaSelection.Contains(e.DepartmentID)
    || exceptions.Contains(e.EmployeeID)

答案 1 :(得分:0)

这里的问题是2100参数限制。这是SQL定义的硬限制。不是ADO.NET或LINQ。几周前我自己跑进了这堵墙。由于LINQ将始终参数化您的查询,因此无法绕过它。您必须批量调用或使用ExecuteQuery。但是如果使用ExecuteQuery,请确保对参数进行自己的验证以避免SQL注入攻击。