有效地进行迭代LINQ to SQL查询

时间:2017-01-11 14:44:53

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

我正在尝试使用LINQ-to-SQL实现以下算法:

给定字符串L的列表,返回DB中的每一行R,其中L中的每个字符串都是R中其中一个列值的子字符串。

问题是我如何迭代地为L中的每个字符串执行此操作?我不知道如何将它全部整合到一个Linq-To-SQL语句中。请注意,我在编写代码时没有问题:

field1.contains(...) || field2.contains(...) || ...

因为没有那么多列。

例如,如果输入是

  

[“查理”,“医生”,“Kor”]

我们将输出所有带有“Charlie”字段作为子字符串的行,带有“Doctor”作为子字符串的字段,以及带有“Kor”作为子字符串的字段。

我想到的一种方法是为每个输入值进行单独的SQL查询,并采用所有这些的交集。

另一种方法是从输入中选择一个字符串,对其进行SQL查询,将其转换为列表,并使用C#中的LINQ一次过滤掉其余字符串。

有关最佳方法的任何想法吗?

2 个答案:

答案 0 :(得分:2)

我会尝试All扩展方法(EF6支持它,不确定LINQ to SQL):

List<string> values = new List<string> { "Charlie", "Doctor", "Kor" };
var query = db.Table
    .Where(r => values.All(v => r.Field1.Contains(v) || r.Field2.Contains(v) || ...));

更新:嗯,假设是错误的 - 正如评论中提到的,不幸的是LINQ to SQL不支持上面的构造(对它们感到羞耻)。

在这种情况下,我会动态构建一个相应的谓词表达式。

在这种特殊情况下,我们需要这样的内容(适用于N字段和M值):

r => (r.Field1.Contains(value1) || r.Field2.Contains(value1) ... || r.FieldN.Contains(value1))
  && (r.Field1.Contains(value2) || r.Field2.Contains(value2) ... || r.FieldN.Contains(value2))
  ...
  && (r.Field1.Contains(valueM) || r.Field2.Contains(valueM) ... || r.FieldN.Contains(valueM));

这是一个自定义扩展方法,它可以做到:

public static class QueryableExtensions
{
    public static IQueryable<T> WhereContainsAll<T>(
        this IQueryable<T> source, 
        IEnumerable<string> values,
        params Expression<Func<T, string>>[] members)
    {
        var parameter = Expression.Parameter(typeof(T), "r");
        var body = values
            .Select(value => members
                .Select(member => (Expression)Expression.Call(
                    Expression.MakeMemberAccess(parameter, ((MemberExpression)member.Body).Member),
                    "Contains", Type.EmptyTypes, Expression.Constant(value)))
                .Aggregate(Expression.OrElse))
            .Aggregate(Expression.AndAlso);
        var predicate = Expression.Lambda<Func<T, bool>>(body, parameter);
        return source.Where(predicate);
    }
}

,样本用法为

List<string> values = new List<string> { "Charlie", "Doctor", "Kor" };
var query = db.Table.WhereContainsAll(values,
    r => r.Field1, r => r.Field2, r => r.Field3, ...);

应该导致单个SQL查询哪个IMO应该是最佳的,因为繁重的工作将由数据库引擎完成。当然,查询很可能会导致全表扫描,但即使使用单Contains(SQL LIKE)条件也会发生同样的情况。

答案 1 :(得分:-1)

试试这个(我使用Lists做了一个例子):

var dbValues = new List<string> {"hello", "how", "are", "you"};
var substrings = new List<string> {"ello", "re"};

var result = dbValues.Where(i => substrings.Any(l => i.Contains(l))).ToList();

结果将包含{“ hello ”,“ ”}

数据库示例:

using (var db = new MyDatabase())
{
    var substrings = new List<string> { "ello", "re" };
    var result = db.MyTable.Where(i => substrings.Any(l => i.Value.Contains(l))).ToList();
}