LINQ用于数组元素的LIKE查询

7
假设我有一个数组,我想对一个varchar执行LINQ查询,返回任何在varchar中包含数组中任何元素的记录。可以像这样实现。
以下是示例代码:
``` string[] industries = { "airline", "railroad" }; var query = from c in contacts where industries.Any(i => c.industry.Contains(i)) select c; ```

LINQ to SQL,LINQ to Entities,LINQ to Objects? - Lucas
5个回答

7

这实际上是我在我的“表达自己”演示中使用的一个例子,用于说明在常规LINQ中难以实现的内容;据我所知,最简单的方法是手动编写谓词。我使用下面的示例(请注意,它同样适用于StartsWith等):

    using (var ctx = new NorthwindDataContext())
    {
        ctx.Log = Console.Out;
        var data = ctx.Customers.WhereTrueForAny(
            s => cust => cust.CompanyName.Contains(s),
            "a", "de", "s").ToArray();
    }
// ...
public static class QueryableExt
{
    public static IQueryable<TSource> WhereTrueForAny<TSource, TValue>(
        this IQueryable<TSource> source,
        Func<TValue, Expression<Func<TSource, bool>>> selector,
        params TValue[] values)
    {
        return source.Where(BuildTrueForAny(selector, values));
    }
    public static Expression<Func<TSource, bool>> BuildTrueForAny<TSource, TValue>(
        Func<TValue, Expression<Func<TSource, bool>>> selector,
        params TValue[] values)
    {
        if (selector == null) throw new ArgumentNullException("selector");
        if (values == null) throw new ArgumentNullException("values");
        if (values.Length == 0) return x => true;
        if (values.Length == 1) return selector(values[0]);

        var param = Expression.Parameter(typeof(TSource), "x");
        Expression body = Expression.Invoke(selector(values[0]), param);
        for (int i = 1; i < values.Length; i++)
        {
            body = Expression.OrElse(body,
                Expression.Invoke(selector(values[i]), param));
        }
        return Expression.Lambda<Func<TSource, bool>>(body, param);
    }

}

不错!(请至少输入10个字符。) - Lucas

4
from c in contracts 
where industries.Any(i => i == c.industry)
select c;

类似这样的。在集合上使用任何方法。


1
这在LINQ to SQL中会抛出异常。它可以写成“where industries.Contains(c.industry)”,这相当于“c.industry IN ('airline', 'railroad')”,但他想要一个LIKE比较。 - Lucas

4

IEnumerable.Contains()被翻译为SQL语句中的IN,如下所示:

WHERE 'american airlines' IN ('airline', 'railroad') -- FALSE

String.Contains() 翻译成 SQL LIKE %...%,例如:

WHERE 'american airlines' LIKE '%airline%' -- TRUE

如果您想获取包含给定行业的联系人,请将Any()和String.Contains()结合起来,例如:
string[] industries = { "airline", "railroad" };

var query = from c in contacts 
            where industries.Any(i => c.Industry.Contains(i))
            select c;

然而,在LINQ to SQL中,将Any()和String.Contains()结合起来使用是不被支持的。如果给定的行业集较小,你可以尝试以下方法:

where c.Industry.Contains("airline") ||
      c.Industry.Contains("railroad") || ...

或者(虽然通常不建议这样做),如果联系人集合足够小,您可以从数据库中将它们全部提取出来,并使用 contacts.AsEnumerable() 或 contacts.ToList() 作为上述查询的数据源来应用 LINQ to Objects 进行过滤:

var query = from c in contacts.AsEnumerable()
            where industries.Any(i => c.Industry.Contains(i))
            select c;

1

如果您按照以下方式构建查询,它将起作用:

var query = from c in contacts.AsEnumerable() select c;

query = query.Where(c=> (c.Industry.Contains("airline")) || (c.Industry.Contains("railroad")));

如果航空公司和铁路公司是用户输入的参数,则只需以编程方式生成上述字符串即可。实际上,这比我预期的要复杂一些。请参阅文章 - http://www.albahari.com/nutshell/predicatebuilder.aspx


0

很遗憾,根据这里,LIKE在LINQ to SQL中不受支持:

http://msdn.microsoft.com/en-us/library/bb882677.aspx

为了解决这个问题,您需要编写一个存储过程,该存储过程将接受您想要在like语句中使用的参数,并从LINQ to SQL中调用它。
应该注意,一些答案建议使用Contains。这是行不通的,因为它只寻找整个字符串与数组元素完全匹配的情况。实际上所要查找的是数组元素是否包含在字段本身中,类似于:
industry LIKE '%<element>%'

正如Clark在评论中提到的那样,您可以对每个元素使用IndexOf调用(这应该转换为SQL调用):
string[] industries = { "airline", "railroad" }

var query = 
    from c in contacts 
    where
        c.industry.IndexOf(industries[0]) != -1 ||
        c.industry.IndexOf(industries[1]) != -1

如果您知道数组的长度和元素数量,那么您可以硬编码它。如果您不知道,则必须根据数组和您正在查看的字段创建Expression实例。

我知道了,我的错。对于数组中的每个项,charindex!= -1就够了。 - Clark
1
实际上,LINQ to SQL 在某种程度上支持 LIKE。"where c.industry.Contains("airline")" 可以工作并且转换为 "WHERE c.industry LIKE '%airline%'"。但是他希望 LIKE 匹配给定的任何值,而不仅仅是一个。 - Lucas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接