【问题标题】:LINQ for LIKE queries of array elements用于数组元素的 LIKE 查询的 LINQ
【发布时间】:2009-03-30 18:12:10
【问题描述】:

假设我有一个数组,我想对一个 varchar 执行 LINQ 查询,该查询返回在 varchar 中任何位置具有数组元素的任何记录。

这样的东西会很甜蜜。

string[] industries = { "airline", "railroad" }

var query = from c in contacts where c.industry.LikeAnyElement(industries) select c

有什么想法吗?

【问题讨论】:

  • LINQ to SQL、LINQ to Entities、LINQ to Objects?

标签: linq arrays linq-to-sql


【解决方案1】:

这实际上是我在“Express Yourself”演示文稿中使用的一个示例,用于在常规 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 个字符。)
【解决方案2】:
from c in contracts 
where industries.Any(i => i == c.industry)
select c;

类似的东西。对集合使用 any 方法。

【讨论】:

  • 这会在 LINQ to SQL 中引发异常。可以写成“where Industries.Contains(c.industry)”,翻译过来就是“c.industry IN('airline', 'railroad')”,但是他想要一个LIKE比较。
【解决方案3】:

IEnumerable.Contains() 转换为 SQL IN,如:

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

String.Contains() 转换为 SQL LIKE %...%,如:

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

如果您想要联系人的行业为 LIKE(包含)任何给定行业的联系人,您希望将 Any() 和 String.Contains() 组合成如下内容:

string[] industries = { "airline", "railroad" };

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

但是,像这样组合 Any() 和 String.Contains() 在 LINQ to SQL 中是 支持的。如果给定行业的集合很小,您可以尝试以下方法:

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;

【讨论】:

    【解决方案4】:

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

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

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

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

    【讨论】:

      【解决方案5】:

      不幸的是,LINQ to SQL 不支持 LIKE,如下所示:

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

      要解决这个问题,您必须编写一个存储过程,该过程将接受您要在 like 语句中使用的参数,然后从 LINQ 到 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 就可以了。
      • 实际上 LIKE 在 LINQ to SQL 中有些支持。 “其中 c.industry.Contains("airline")” 有效并转换为“WHERE c.industry LIKE '%airline%'。但他想要 LIKE 任何给定值,而不仅仅是一个。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 2018-11-16
      • 1970-01-01
      相关资源
      最近更新 更多