【问题标题】:How to "split up" or optimize a Linq to Sql query.如何“拆分”或优化 Linq to Sql 查询。
【发布时间】:2014-04-11 23:35:33
【问题描述】:

背景

我们有一个AdvancedSearchModel,它只是一个包含多个字符串的结构。 SerialNumbers 是一串以逗号分隔的序列号(长度为 10 个字符)。这被分成一个字符串数组。我们正在搜索一个表Devices,其中有一列SerialNumber。我们还需要部分匹配这些搜索短语,这解释了AnyContains 的用法。 AdvancedSearchModel 中有大约 10 个字符串,我们可以毫无问题地将每个字符串应用于查询。

public static IQueryable<Device> ApplySearchQuery(IQueryable<Device> query, AdvancedSearchModel searchModel)
{
    if (!String.IsNullOrWhiteSpace(searchModel.SerialNumbers))
    {
        string[] serialNumbers = searchModel.SerialNumbers.Split(',');
        query = query.Where(d => serialNumbers.Any(s => d.SerialNumber.Contains(s))); 

     }
     // ... more queries added that are part of the search model
}

问题

让我先介绍一下,当它被实施时,我们预计一次最多可以搜索 10 个序列号。 但是,我们发现用户最多可以输入 100 个序列号。我们得到一个错误,即查询嵌套太深。所以即使我们只按 SerialNumbers 搜索,当serialNumbers 超过 43 个元素时,它也会抛出异常。

我不太确定如何拆分此查询,因为它们很简单(尽管我们预计结果会很慢)。

也许我们可以有一个大小约为 25 的 string[]ArrayList,并扩大这个数组列表,即如果用户搜索 100 个序列号,那么 ArrayList 将有 4 个字符串数组,但我我不确定这是否真的有帮助...

有什么想法吗?

【问题讨论】:

  • 不能把序列号拆分成25个序列号的批次进行多次搜索吗?
  • 我目前正在尝试这个^,但它似乎不是很优雅。
  • 当数组超过 43 个连续序列时,您会遇到什么异常?
  • System.Data.EntityCommandExecutionException - 您的 SQL 语句的某些部分嵌套得太深。重写查询或将其分解为更小的查询
  • @JoachimIsaksson Batching 似乎正在工作,我猜我会把它添加为答案。

标签: c# linq entity-framework linq-to-sql


【解决方案1】:

如果您手动生成 OR 表达式,我想您可以让 EF 生成平面 OR 语句而不是嵌套子查询:

string[] serialNumbers = searchModel.SerialNumbers.Split(',');
// GetMethod defined at http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/
var stringContainsMethod = Helpers.GetMethod((string s) => s.Contains(default(string)));
var serialNumberProperty = Helpers.GetProperty((Device d) => d.SerialNumber);
var parameter = Expression.Parameter(typeof(Device));

// generate a condition d.SerialNumber.Contains(sn) for each sn
var conditions = serialNumbers.Select(sn => Expression.Call(  
    Expression.MakeMemberAccess(parameter, serialNumberProperty), // d.SerialNumber
    stringContainsMethod, // the method to invoke
    Expression.Constant(sn) // equivalent of a string literal for the serial number
));

// generate a lambda we can pass to Where: 
// d => d.SerialNumber.Contains(sn1) || d.SerialNumber.Contains(sn1) || ..
var predicate = Expression.Lambda<Func<Device, bool>>(
    // merge each condition with ORs
    conditions.Aggregate<Expression>((c1, c2) => Expression.OrElse(c1, c2)),
    parameter
);

// apply the predicate
query = query.Where(predicate);

当然,批处理也可以。但是,对于这么小的参数集,应该没有必要。

【讨论】:

  • 这很有趣,我会试试这个。
  • GetProperty 是什么类的函数?我在代码鸭子命名空间中看不到它。
  • 我得到了这个工作,我实现了 GetProperty 函数......虽然我想进一步了解它是如何工作的!
  • @Dave:正如您所猜测的那样,GetProperty 只是 GetMethod() 的另一个变体,并且具有非常相似的实现。就更好地理解事物而言,您对哪一部分有疑问?
  • 创建条件有点混乱。 Expression.Constant(sn) 是做什么的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多