繁体   English   中英

如何动态组合linq查询?

[英]How to combine a linq query dynamically?

假设我有一个表,在字符串( nvarchar )列中包含格式化的值。 这些值应该是由某些const符号分隔的字符串(请使用分号; )。 例如,

12;0;5;dog //four values separated by a semi-colon

要么

053 //if there is only one value, no semi-colon at the end

分隔符始终是分隔符,不能成为值的一部分。

我需要检查该表中是否已经有一行,并且该列中的值列表至少包含指定的一项。 换句话说,我有一个值列表:

List<string> list = new List<string>() { "somevalue1", "somevalue2" };

分隔符:

string separator = ";";

我需要编写一个linq-to-sql查询来执行此操作:

select ... from sometable
where Value='somevalue1' or Value like 'somevalue1;%' or
      Value like '%;somevalue1' or Value like '%;somevalue1;%'

   or Value='somevalue2' or Value like 'somevalue2;%' or 
      Value like '%;somevalue2' or Value like '%;somevalue2;%'

应该提到的是,任何搜索值都可以包含其他值。 也就是说,我可能正好搜索5 ,而某行可能包含1;15;55 这样的行不能匹配。 ...;5;...或只是55;......;5是匹配项。

使用linq-to sql我知道如何进行以下类型的查询:

select ... from sometable where (... or ... or ...) and (... or ...) ...

那是

IQueryable<SomeTable> query = dc.SomeTable;
foreach (string l in list)
{
    string s = l;
    query = query.Where(b => b.Value.StartsWith(s + separator) ||
                             b.Value.EndsWith(separator + s) ||
                             b.Value.Contains(separator + s + separator) ||
                             b.Value.Equals(s));
}
if (query.Any()) {/*...*/}

显然, Where语句在结果sql查询中用AND连接,而我到处都需要OR

那么有没有办法在C#代码中获取我需要的查询? 还是唯一的方法是使用手写查询和DataContext.ExecuteQuery方法来执行此操作?

我想UNION可以满足您的需求:

IQueryable<SomeTable> baseQuery = dc.SomeTable;
IQueryable<SomeTable> query = new List<SomeTable>().AsQueryable();
foreach (string l in list)
{
    string s = l;

    query.Union(baseQuery.Where(b => b.Value.StartsWith(s + separator) ||
                             b.Value.EndsWith(separator + s) ||
                             b.Value.Contains(separator + s + separator) ||
                             b.Value.Equals(s)));
}
if (query.Any()) {/*...*/}
public static Expression<Func<T, bool>> OrTheseFiltersTogether<T>(
  this IEnumerable<Expression<Func<T, bool>>> filters)
{
    Expression<Func<T, bool>> firstFilter = filters.FirstOrDefault();
    if (firstFilter == null)
    {
        Expression<Func<T, bool>> alwaysTrue = x => true;
        return alwaysTrue;
    }

    var body = firstFilter.Body;
    var param = firstFilter.Parameters.ToArray();
    foreach (var nextFilter in filters.Skip(1))
    {
        var nextBody = Expression.Invoke(nextFilter, param);
        body = Expression.OrElse(body, nextBody);
    }
    Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(body, param);
    return result;
}

因此,您可以从输入集中轻松构建过滤器列表:

List<string> list = new List<string>() { "somevalue1", "somevalue2" };
List<Expression<Func<SomeTable, bool>>> equalsFilters = list
  .Select(s => row => row.Value == s).ToList();
List<Expression<Func<SomeTable, bool>>> startsWithFilters = list
  .Select(s => row => row.Value.StartsWith(s + ";")).ToList();
List<Expression<Func<SomeTable, bool>>> endsWithFilters = list
  .Select(s => row => row.Value.EndsWith(";" + s).ToList();
List<Expression<Func<SomeTable, bool>>> middleFilters = list
  .Select(s => row => row.Value.Contains(";" + s + ";")).ToList();

Expression<Func<SomeTable, bool>> theFilter = OrTheseFiltersTogether(
  equalsFilters.Concat(startsWithFilters).Concat(endsWithFilters).Concat(middleFilters)
);

query = query.Where(theFilter);

暂无
暂无

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

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