繁体   English   中英

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

[英]Efficiently make iterative LINQ to SQL queries

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

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

问题是如何对 L 中的每个字符串迭代地执行此操作? 我不知道如何巧妙地将它们全部放入一个 Linq-To-SQL 语句中。 请注意,我可以按照以下方式编写代码:

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

因为没有那么多列。

例如,如果输入是

[“查理”、“医生”、“科尔”]

我们将输出具有“Charlie”作为子字符串的字段、“Doctor”作为子字符串的字段和“Kor”作为子字符串的字段的所有行。

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

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

关于执行此操作的最佳方法的任何想法?

我会尝试所有扩展方法(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, ...);

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

试试这个(我用列表做了一个例子):

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 "," are "}

数据库示例:

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();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM