Linq to Entities Where Or 子句

Linq to Entities Where Or clause

已阅读类似问题的其他回复,但我无法使用 PredicateBuilder,也无法复制其源代码。我正在尝试我在这里阅读的内容:

<https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/

但由于我是新手,在将我正在阅读的内容翻译成我正在申请的内容时遇到了问题。我创建了一个 L2E 查询,并尝试将一系列 OR 子句附加到 WHERE:

所以作为简化的片段(这个片段将与之前已经定义的 WHERE 子句进行 AND 运算):

if (firstParm == "realtor")
    query = query.Where(x=> x.A == "realtor");

现在尝试或:

if (secondParm == "clown")
   // how to add this one as an OR to the above query:
   query = query.OR(x=> x.fool == "clown");

我知道这也可以用 Union 来完成,但语法不清楚:

query = query.Union(x=> x.fool == "clown");  // ??

我也参考过:

Combining two expressions (Expression<Func<T, bool>>)

Unable to create a compound Expression<Func<string, bool>> from a set of expressions

不过,我还是 LINQ 的新手,尤其是表达式树,所以需要更多的填充。

或者你可以试试

  if (secondParm == "clown") 
  {
    query = query.Where(x=> x.fool == "clown" || x.fool==x.fool);
  }

  if (secondParm == "clown") 
  {
    query = query.Where(x=> x.fool == "clown" || true );
  }

有两种生成表达式的方法。

  1. 用编译器来做。

    Expression<Func<Person, bool>> = p => p.LastName.Contains("A");
    

    限制:可以这种方式生成的唯一表达式是 LambdaExpression 的实例。另外,提取部分表达式并与其他部分组合起来相当复杂。

  2. 使用 System.Linq.Expressions.Expression 处的静态方法。


为了生成动态表达式,您可以选择不同的编译器生成的表达式:

// using Record and Records as a placeholder for the actual record type and DbSet property

Expression<Func<Record,bool>> expr;
if (firstParam == "realtor") {
    if (secondParam == "clown") {
        expr = x => x.A == "realtor" || x.fool == "clown";
    } else {
        expr = x => x.A == "realtor";
    }
} else {
    if (secondParam == "clown") {
        expr = x => x.fool="clown";
    } else {
        expr = x => false;
    }
}

var ctx = new MyDbContext();
var qry = ctx.Records.Where(expr).Select(x => new {x.A, x.fool});

或者,您可以使用静态方法动态创建表达式:

(将 using System.Linq.Expressions;using static System.Linq.Expressions.Expression; 添加到文件顶部。)

Expression expr;
var parameter = Parameter(typeof(Record));
if (firstParam == "realtor") {
    expr = Equals(
        MakeMemberAccess(parameter, typeof(Record).GetProperty("A")),
        Constant("realtor")
    );
}
if (secondParam == "clown") {
    var exprClown = Equals(
        MakeMemberAccess(parameter, typeof(Record).GetProperty("fool")),
        Constant("clown")
    );
    if (expr == null) {
        expr = exprClown;
    } else {
        expr = Or(expr, exprClown);
    }
}

var lambda = Lambda<Func<Record,bool>>(expr, new [] {parameter});
var ctx = new MyDbContext();
var qry = ctx.Records.Where(lambda).Select(x => new {x.A, x.fool});

给定一个编译时类型未知的查询,因此引用它的任何变量都必须是 IQueryable,而不是 IQueryable<T>:

IQueryable qry = ctx.GetQuery(); //dynamically built query here
var parameter = Parameter(qry.ElementType);
if (firstParam == "realtor") {
    expr = Equals(
        MakeMemberAccess(parameter, qry.ElementType.GetProperty("A")),
        Constant("realtor")
    );
}
if (secondParam == "clown") {
    var exprClown = Equals(
        MakeMemberAccess(parameter, qry.ElementType.GetProperty("fool")),
        Constant("clown")
    );
    if (expr == null) {
        expr = exprClown;
    } else {
        expr = Or(expr, exprClown);
    }
}

var lambda = Lambda(expr, new [] {parameter});

//Since we don't have access to the TSource type to be used by the Where method, we have
//to invoke Where using reflection.
//There are two overloads of Queryable.Where; we need the one where the generic argument
//is Expression<Func<TSource,bool>>, not Expression<Func<TSource,int,bool>>
var miWhere = typeof(Queryable).GetMethods().Single(mi => {
    mi.Name == "Where" && 
        mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2
});

qry = miWhere.Invoke(null, new [] {qry, lambda});