[英]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.