frododot
frododot

Reputation: 127

Linq to Entities Where Or clause

Have read other responses to similar issuebut I can not use PredicateBuilder, or copy its source. I'm trying what I've read here:

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

but as I'm newb, am having trouble with translating what I'm reading to what I'm applying. I have created a L2E query, and trying to append a series of OR clauses onto the WHERE:

So as simplified snippet (this one will be AND'd with the previously already defined WHERE clause):

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

Now trying to OR:

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

I understand this can be done also with Union, but not clear on the syntax:

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

I've also referenced:

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

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

but again, I am new to LINQ and especially Expression Trees, so need more fillin.

Upvotes: 1

Views: 1511

Answers (2)

Zev Spitz
Zev Spitz

Reputation: 15317

There are two ways to generate expressions.

  1. Use the compiler to do it.

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

    Limitations: The only expressions that can be generated this way are instances of LambdaExpression. Also, it is rather complicated to extract parts of the expression and combine with other parts.

  2. Use the static methods at System.Linq.Expressions.Expression.


In order to generate dynamic expressions, you can either choose between different compiler-generated expressions:

// 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});

Or, you can dynamically create the expression using the static methods:

(Add using System.Linq.Expressions; and using static System.Linq.Expressions.Expression; to the top of the file.)

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});

Given a query with a type unknown at compile time, so any variable referring to it must be IQueryable only, and not 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});

Upvotes: 2

vibhuti
vibhuti

Reputation: 11

For Or you can try

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

OR

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

Upvotes: 0

Related Questions