LINQ 2 SQL - 使用C#实体集合和SqlMethods.Like在一起

时间:2017-01-19 11:29:05

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

我有一个标题集合,每个标题都包含一组对象,每个对象都包含一组元数据键值对。例如

> Header
>     -> Object
>         -> Key value pair
>         -> Key value pair
>     -> Object
>         -> Key value pair
>         -> Key value pair

我想使用SQL通配符(使用SqlMethods.Like)返回包含对象的所有标头,其中包含元数据中的某个键值对。

我在下面编写了一个LINQ 2 SQL查询,其中有两个级别的子查询处理方案

string filePath = "ab%cd";
var dbHeaders = from h in _repository.GetHeaders()
                    where
                         (from o in h.Objects
                          where 
                                (from mdp in o.MetaDataPairs 
                                 where mdp.Key == Constants.FilePath && SqlMethods.Like(mdp.Value.ToLower(), filePath)) 
                                 select mdp
                                ).Any()
                          select o).Any()
                     select h;

这很好用。

当我有一个可供搜索的搜索值列表时,会出现问题。即我想从可能的匹配列表中找到包含元数据值的对象,而不仅仅是单个匹配。我尝试了下面的内容。

var filePaths = new List<string> { "ab%cd", "ef%gh" };
var dbHeaders = from h in _repository.GetHeaders()
                    where
                         (from o in h.Objects
                          where 
                                (from mdp in o.MetaDataPairs 
                                 where mdp.Key == Constants.FilePath && filePaths.Any(fp => SqlMethods.Like(mdp.Value.ToLower(), fp)) 
                                 select mdp
                                ).Any()
                          select o).Any()
                     select h;

但是因为SQLMethods.Like包含在Filepaths.Any()中,所以它不起作用。因为它必须在LINQ 2 SQL查询中本地发生。

如何使用SQL Like运算符修改要匹配的顶级查询,以便检查字符串搜索令牌列表,而不是单个?

更新:错误消息

  

Assert.IsFalse失败。发生意外错误:LINQ to Entities   无法识别方法&#39;布尔类似(System.String,   System.String)&#39;方法,这个方法无法翻译成一个   商店表达。

1 个答案:

答案 0 :(得分:0)

正如您所提到的,问题是,一旦您将SqlMethods.Like放入filePaths.Any,它就会引发异常。 这是因为linq-to-entity不支持SqlMethods.LikefilePath是实体。

您需要以某种方式使用OR动态创建多个SqlMethods.Like语句。

我发现了一个非常相似的问题和一个应该有用的有趣答案: How can I add variable count of SqlMethods.Like() in one query?

该解决方案利用了来自 C#6.0 in Nutshell PredicateBuilder

我相信您可以将您的代码调整为以下内容:
我没有测试代码,当然。

var filePaths = new List<string> { "ab%cd", "ef%gh" };
var likeExpression = PredicateBuilder.False<MetaDataPairClassName>();
foreach (string filePath in filePaths)
{
    likeExpression = likeExpression.Or(mdp => 
    SqlMethods.Like(mdp.Value.ToLower(), filePath));
}

var dbHeaders = from h in _repository.GetHeaders()
                where
                   (from o in h.Objects
                     where 
                        (from mdp in o.MetaDataPairs
                         .Where(mdp.Key == Constants.FilePath)
                         .Where(likeExpression)) 
                         select mdp
                              ).Any()
                     select o).Any()
                select h;