LINQ查询中的C#多个OR条件[重复]
Posted
技术标签:
【中文标题】LINQ查询中的C#多个OR条件[重复]【英文标题】:C# multiple OR conditions in LINQ query [duplicate] 【发布时间】:2021-08-07 09:47:25 【问题描述】:我正在尝试使用 LINQ 链接多个值或循环。
情况
平台:.net 5
C# 9
我们正在为列表构建过滤逻辑。在当前情况下,它涉及要过滤的字符串值。 用户可以搜索一个或多个值。他可以决定单个搜索词是否为 AND/OR 链接,以及某个值是否为否定。
我看到了这个条目。但由于我的值在循环中,我不能使用||
。https://***.com/a/37195788/1847143
例子:
名称中带有“A”的所有动物SELECT * FROM "Animal" WHERE "Name" = 'A';
名称中带有“A”或“B”的所有动物SELECT * FROM "Animal" WHERE "Name" = 'A' OR "Name" = 'B';
名称中包含“A”或“B”或非“C”的所有动物(这将是毫无意义的搜索)SELECT * FROM "Animal" WHERE "Name" = 'A' OR "Name" = 'B' OR "Name" != 'C' ;
名称中带有“A”和“B”的所有动物SELECT * FROM "Animal" WHERE "Name" = 'A' AND "Name" = 'B';
名称中包含“A”和“B”而不是“C”的所有动物SELECT * FROM "Animal" WHERE "Name" = 'A' AND "Name" = 'B' AND "Name" != 'C';
问题
与 LINQ 的 AND 链接没有问题。但是这些值如何与 OR 联系起来呢?
代码示例
using System.Collections.Generic;
using System.Linq;
namespace SampleProject
public class Program
public static void Main(string[] args)
// Or Condtion
Condition condition = Condition.Or;
var animalsQuery = Animals.AsQueryable();
// Loop over all search values to extend the query
foreach (FilterValue filterValue in FilterValues)
switch (filterValue.LikeType)
case LikeType.Left: // LIKE '%value'
animalsQuery = filterValue.IsNegated
? animalsQuery.Where(animal => !animal.Name.EndsWith(filterValue.Value))
: animalsQuery.Where(animal => animal.Name.EndsWith(filterValue.Value));
break;
case LikeType.Right: // LIKE 'value%'
animalsQuery = filterValue.IsNegated
? animalsQuery.Where(animal => !animal.Name.StartsWith(filterValue.Value))
: animalsQuery.Where(animal => animal.Name.StartsWith(filterValue.Value));
break;
case LikeType.LeftAndRight: // LIKE '%value%'
animalsQuery = filterValue.IsNegated
? animalsQuery.Where(animal => !animal.Name.Contains(filterValue.Value))
: animalsQuery.Where(animal => animal.Name.Contains(filterValue.Value));
break;
case LikeType.Equals: // Like 'value'
animalsQuery = filterValue.IsNegated
? animalsQuery.Where(animal => animal.Name != filterValue.Value)
: animalsQuery.Where(animal => animal.Name == filterValue.Value);
break;
var result = animalsQuery.ToList();
/// Values to filter
public static List<Animal> Animals = new()
new() Name = "Lenny",
new() Name = "Gideon",
new() Name = "Shania",
new() Name = "Jada",
new() Name = "Kamil",
new() Name = "Fariha",
;
/// Search Values
public static List<FilterValue> FilterValues = new()
new() Value = "a", LikeType = LikeType.Left,
new() Value = "n", LikeType = LikeType.Right,
new() Value = "f", LikeType = LikeType.LeftAndRight,
new() Value = "k", LikeType = LikeType.Equals,
;
public class Animal
public string Name get; set;
public class FilterValue
public string Value get; set;
public bool IsNegated get; set;
public LikeType LikeType get; set;
public enum LikeType
Left = 1,
Right = 2,
LeftAndRight = 3,
Equals = 4,
public enum Condition
And = 1,
Or = 2,
【问题讨论】:
如果OR
都等于而不是不等于,那么问题很简单——使用Contains
(即有一个List<string>
的值)。 !=
唉,这不会那么好。
与其链接多个 Where
调用,不如为每个条件创建一个 lambda,将这些 lambda 与 &&
和/或 ||
运算符组合,然后使用组合结果进行一个 Where
调用.
你可能需要一个 PredicateBuilder;即可以创建和组合 linq 查询谓词的类。它通常包括 OR、AND、NOT、XOR、TRUE 和 FALSE 的方法。它的输入是针对项目类的属性名称或 lambda getter 表达式(在您的示例中为“Animal”)。
@mjwills 但是这样我不能将StartsWith
与EndsWith
结合起来。所有“以 A 开头”和“以 E 结尾”的动物。 SELECT * FROM "Animal" WHERE "Name" LIKE 'A%' AND "Name" LIKE '%E';
@TheBigNeo 没错。
【参考方案1】:
这进入了表达式树重写的领域。好消息是:它不是非常复杂并且你可以同时执行你的否定步骤:
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
namespace SampleProject
public class Program
static Expression<Func<T, bool>> Combine<T>(Condition condition, Expression<Func<T, bool>> left, Expression<Func<T, bool>> right, bool negateRight)
if (right is null) return left;
if (left is null)
return negateRight ?
Expression.Lambda<Func<T, bool>>(
Expression.Not(right.Body), right.Parameters)
: right;
var leftP = left.Parameters.Single();
var rightP = right.Parameters.Single();
var rightBody = right.Body;
if (!ReferenceEquals(leftP, rightP))
// swap all uses of rightP on rightBody to leftP
// i.e. normalize on the parameter
rightBody = new SwapVisitor(rightP, leftP).Visit(rightBody);
if (negateRight)
rightBody = Expression.Not(rightBody);
return Expression.Lambda<Func<T, bool>>(condition switch
Condition.And => Expression.AndAlso(left.Body, rightBody),
Condition.Or => Expression.OrElse(left.Body, rightBody),
_ => throw new ArgumentOutOfRangeException(nameof(condition)),
, left.Parameters);
class SwapVisitor : ExpressionVisitor
private readonly Expression _from, _to;
public SwapVisitor(Expression from, Expression to)
_from = from;
_to = to;
public override Expression Visit(Expression node)
=> ReferenceEquals(node, _from) ? _to : base.Visit(node);
public static void Main(string[] args)
// Or Condtion
Condition condition = Condition.Or;
var animalsQuery = Animals.AsQueryable();
// Loop over all search values to extend the query
Expression<Func<Animal, bool>> predicate = null;
foreach (FilterValue filterValue in FilterValues)
switch (filterValue.LikeType)
case LikeType.Left: // LIKE '%value'
predicate = Combine(condition, predicate, animal => animal.Name.EndsWith(filterValue.Value), filterValue.IsNegated);
break;
case LikeType.Right: // LIKE 'value%'
predicate = Combine(condition, predicate, animal => animal.Name.StartsWith(filterValue.Value), filterValue.IsNegated);
break;
case LikeType.LeftAndRight: // LIKE '%value%'
predicate = Combine(condition, predicate, animal => animal.Name.Contains(filterValue.Value), filterValue.IsNegated);
break;
case LikeType.Equals: // Like 'value'
predicate = Combine(condition, predicate, animal => animal.Name == filterValue.Value, filterValue.IsNegated);
break;
if (predicate is not null)
animalsQuery = animalsQuery.Where(predicate);
var result = animalsQuery.ToList();
/// Values to filter
public static List<Animal> Animals = new()
new() Name = "Lenny" ,
new() Name = "Gideon" ,
new() Name = "Shania" ,
new() Name = "Jada" ,
new() Name = "Kamil" ,
new() Name = "Fariha" ,
;
/// Search Values
public static List<FilterValue> FilterValues = new()
new() Value = "a", LikeType = LikeType.Left ,
new() Value = "n", LikeType = LikeType.Right ,
new() Value = "f", LikeType = LikeType.LeftAndRight ,
new() Value = "k", LikeType = LikeType.Equals ,
;
public class Animal
public string Name get; set;
public class FilterValue
public string Value get; set;
public bool IsNegated get; set;
public LikeType LikeType get; set;
public enum LikeType
Left = 1,
Right = 2,
LeftAndRight = 3,
Equals = 4,
public enum Condition
And = 1,
Or = 2,
【讨论】:
非常感谢。这完美地工作。Combine
开头有个小bug。如果第一个/单个right
值是left == null
和right != null
和negateRight == true
,那么right
不会被否定。 if (left is null) return negateRight ? Expression.Lambda<Func<T, bool>>(Expression.Not(right.Body), right.Parameters) : right;
@TheBigNeo 够公平的!以上是关于LINQ查询中的C#多个OR条件[重复]的主要内容,如果未能解决你的问题,请参考以下文章