[英]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;...
或只是5
或5;...
或...;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.