在运行时修改linq查询

时间:2013-03-18 14:05:21

标签: c# linq entity-framework extension-methods

问题陈述

说我有一个搜索人名的查询:

var result = (from person in container.people select person)
             .Where(p => p.Name.Contains(some_criterion)

这将转换为包含以下like子句的SQL查询:

WHERE NAME LIKE '%some_criterion%'

这有一些性能影响,因为数据库无法有效地使用name列上的索引(索引扫描v.s.索引搜索,如果我没有弄错的话)。

为了解决这个问题,我可以决定只使用StartsWith(),使用类似的子句生成查询:

WHERE NAME LIKE 'some_criterion%'

这使SQL Server能够以某些功能为代价使用索引查找和提供性能。

我希望能够为用户提供一个选择:默认行为使用StartsWith,但是如果用户希望使用Contains()进行搜索的“增加的灵活性”,那么应该使用。

我尝试了什么

我认为这是微不足道的,并继续在字符串上实现了一个扩展方法。但是,当然,LINQ不接受这个并抛出异常。

现在,我当然可以使用if或switch语句并为每个案例创建一个查询,但我更倾向于在更高级别或更一般地解决这个问题。 简而言之:由于现实应用程序的复杂性,使用if语句来区分用例是不可行的。这会导致很多重复和混乱。我真的希望能够以某种方式封装变化的行为(Contains,StartsWith,EndsWith)。

问题

我应该在哪里寻找或者我应该寻找什么?这是与IQueryables的可组合性的案例吗?我很困惑!

3 个答案:

答案 0 :(得分:8)

不是过于复杂化,而是使用if语句怎么样?

var query = from person in container.people 
            select person;

if (userWantsStartsWith)
{
    query = from p in query
            where p.Name.Contains(some_criterion)
            select p;
}
else
{
    query = from p in query
            where p.Name.StartsWith(some_criterion)
            select p;
}

<强>更新

如果你真的需要更复杂的东西,请试试LinqKit。它允许您执行以下操作。

var stringFunction = Lambda.Expression((string s1, string s2) => s1.Contains(s2));

if (userWantsStartsWith)
{
    stringFunction = Lambda.Expression((string s1, string s2) => s1.StartsWith(s2));
}

var query = from p in container.people.AsExpandable()
            where stringFunction.Invoke(p.Name, some_criterion)
            select p;

我相信这符合您的要求

  

我真的希望能够封装变化的行为   (包含,StartsWith,EndsWith)不知何故。

答案 1 :(得分:2)

您可以在枚举之前动态更改查询。

var query = container.people.AsQueryable();

if (contains)
{
    query = query.Where(p => p.Name.Contains(filter));
}
else
{
    query = query.Where(p => p.Name.StartsWith(filter));
}

答案 2 :(得分:0)

尝试dis:

var result = (from person in container.people select person)
                .Where(p => some_bool_variable ? p.Name.Contains(some_criterium) : p.Name.StartsWith(some_criterium));

现实生活中的查询非常庞大,并与其他几个人联合起来。就像我的问题所说的那样,这不是我正在寻找的解决方案

Sinse你的查询是巨大的:你不能只定义处理所有内容的存储过程并使用特定于查询参数调用它(可能是由main调用的几个存储过程,例如,按名称搜索em,另一个 - 通过年龄,有不同的排序顺序等等以保持代码清晰)?