我正在尝试使用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));
有什么办法吗?感谢。
答案 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注入攻击。