【问题标题】:LinqToSQL In ClauseLinq To SQL In 子句
【发布时间】:2011-06-16 03:00:10
【问题描述】:

我正在尝试使用 LinqToSQL 生成一个可能包含很多项目的 IN 子句。我原来的代码是这样的:

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

最终生成一个 in 子句,其中每个员工 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));

有什么办法吗?谢谢。

【问题讨论】:

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


    【解决方案1】:

    您是否可以定义一个查询,该查询将根据其他查询返回所需的员工 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)
    

    【讨论】:

    • 您可能会使用 join 而不是嵌套查询来包含示例的另一个版本。只是一个建议,因为我发布的内容与您的类似。
    • 在我的案例中,员工 ID 由用户提供。他们会看到员工列表并选择他们想要的员工。所以我认为这行不通。
    • 我想过像您建议的那样尝试使查询更智能。我不确定这是否会奏效。我看到了包含用户不想要的记录的可能性。例如,用户看到所有活跃员工的列表,然后其他人更新活跃数据,然后第一个用户执行某些操作以查看结果,现在它包括错误的员工。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2010-10-25
      • 2023-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-23
      • 2018-04-22
      相关资源
      最近更新 更多