LINQ Dynamic Assignment Expressions - c#

I have the following code that I would rather have defined dynamically.
var candidates = People.Where(x=> (x.Age >18 && x.Age < 25)) .AsQueryable().Select( c=> { c.Category = "F190 MISSING" ; return c; });
What I would however want is to have the above assignment defined as a string to be executed at runtime like so
String Conditional= "c=> { c.Category = #0; return c; }";
String[] ExpressionParameters = new [] {"F190 MISSING"};
var candidates = People.Where(x=> (x.Age >18 && x.Age < 25)).AsQueryable().Select( Conditional,ExpressionParameters);
So far, with my attempts, I have been getting either a Expression expected error message or a NO PROPERTY C EXISTS IN PERSON. How can I better define my assignment expression dynamically? Thanks in advance.

The first one does not work, because c# compiler is not able to transform multi-line lambda into Expression Tree (and IQueryable.Select expects expression).
The C# and Visual Basic compilers can generate expression trees only
from expression lambdas (or single-line lambdas). It cannot parse
statement lambdas (or multi-line lambdas). For more information about
lambda expressions in C#, see Lambda Expressions (C# Programming
Guide); (...).
The second one can be done using libraries like DynamicLINQ.

Related

Creating an (Lambda) Expression using recursion

I have the following dictionary:
Dictionary<string, PropertyInfo> filterProperties;
The content of this dictionary can be like this:
- "Language": [QueryData.Lang],
- "Id": [Querydata.UserId]
Each string key maps to a property of a my QueryData type.
Now let's suppose I have the following QueryData instance:
QueryData: { Lang= "en", UserId = "mcicero" }
Using the previous dictionary as example, I want to build the following expression:
e => e.Language == "en" && e.Id == "mcicero";
As you can see the dictionary keys are used for accesing the properties of e, and the dictionary values (QueryData properties) are used for specifying constants in the binary equal expressions.
e is of type Entity, and is guaranteed to have this properties.
The resulting expression should be of type Expression<Func<Entity, bool>>
How can I build this expression using recursion?
I say recursion because it sounds like a natural solution, but an iterative one would be preferred.
I tried the iterative alternative and ended up with an ugly and not so understandable code.
However, I am having trouble creating a recursion method for this problem.
Leaving the creation of the individual expression to you, simply combine them together in an iterative loop:
// For an IEnumerable<Expression> in "expressions"
Expression left = null;
foreach(var right in expressions)
{
if(left == null)
left = right;
else
left = Expression.And(left, right);
}
// Combined expression is in "left"
// Don't forget it will be null if there were no expressions provided...
Or in one line with LINQ:
var expr = expressions.Aggregate(Expression.And);
For the interested ones, in one single line:
Expression expr = filterProperties.Select(i => Expression.Equal(
Expression.Property(entityParameter, i.Key),
Expression.Constant(i.Value.GetValue(queryObj))
)).Aggregate(Expression.And);

Search records with code pattern in column value c#

I have one code of employee which is A-B-C-D- . Now I want to search all records which are starting with A- till it rich A-B-C-D-. I have tried below code:
var result = db.Employee.Where(x=> x.EmployeeCode.StartsWith("A-B-C-D-"));
Above code gives me only one record. But I want all records which starts with A- then A-B- then A-B-C- and then equals to A-B-C-D-.
Any hint or idea is appreciated.
Have you tried this?
var result = db.Employee
.Where(x=> x.EmployeeCode.StartsWith("A-")
|| x.EmployeeCode.StartsWith("A-B-")
|| x.EmployeeCode.StartsWith("A-B-C-")
|| x.EmployeeCode.StartsWith("A-B-C-D-");
As you say in the comment that it must be dynamic, then do something like this:
string code = "A-B-C-D-";
var predicates = new List<Expression<Func<Customer,bool>>>();
for (int i = 0; i < code.Length; i++)
{
if (code[i] == '-')
{
var prefix = code.Substring(0, i + 1);
predicates.Add(x => x.EmployeeCode.StartsWith(prefix));
}
}
var oredPredicates = ...; // Keep reading!
...
var result = db.Employee.Where(oredPredicate);
Now, you have a lis of predicates, and have to combine them with || (or). To do so it's a bit messy, but there are solutions, for example like in this SO Q&A's:
Combining two expressions (Expression>)
Combine two Linq lambda expressions
How can I combine two lambda expressions without using Invoke method?
C# how to combine two expressions into a new one?
Once you have all the predicates combined, use it as parameter for your .Where() function.
Unfortunately the most complicated part of combining the expressions is unavoidable, and it's the toughest part to solve this problem, but it works. Please, read the 3 Q&A's, to get insight in what you're doing and get the code that best suits you (beware that using the simple Expression.OrAlso would not directly work, because the x param in each lambda is different for each created expression)

LINQ TO ENTITIES USING PREDICATE(Func(x,bool) Not Working

I have a Where clause predicate which is fetching records .Now if I use the same in a where clause as a Predicate(ie Func(x,bool) ) it returns no records.My impression was that both were equivalent. - see below
var nonPredicate=this.ObjectSet.Where(x=>!String.IsNullOrEmpty(x.Email) && x.Email.Contains("AND")).ToList();
Func<Model,bool) clause=x=> x=>!String.IsNullOrEmpty(x.Email) && x.Email.Contains("AND");
var predicateRes=this.ObjectSet.Where(clause).ToList();
I expected same results in both cases -but the first produces 29 record result and the second 0 records.
Any Help would be great
Thanks
Linq to Entitites uses Expression<Func<?,?>> for it's query methods. Lambda expressions are automatically coersed to an expression (Expression<Func<?,?>>) or delegate (Func<?,?>) depending on the type of the variable or argument it is stored in.
// Inline expression
var nonPredicate = this.ObjectSet.Where(x =>
!string.IsNullOrEmpty(x.Email) && x.Email.Contains("AND")).ToList();
// Delegate type
Func<Model,bool> clauseDelegate = x =>
!string.IsNullOrEmpty(x.Email) && x.Email.Contains("AND");
// Expression type
Expression<Func<Model,bool>> clauseExpr = x =>
!string.IsNullOrEmpty(x.Email) && x.Email.Contains("AND");
var predicateRes = this.ObjectSet.Where(clauseExpr).ToList();
Expressions are an object representation of the lambda, which allows the library to translate it into SQL for communication with the database. The same is not possible with delegates, since the structure is already compiled into IL or machine code.

Nesting PredicateBuilder predicates : 'The parameter 'f' was not bound in the specified LINQ to Entities query expression'

I am building predicates using LinqKit's PrediateBuilder class to dynamically setup filters and I want to combine a nested one to another.
I have read this (http://www.albahari.com/nutshell/predicatebuilder.aspx) :
Here is my code :
// The main predicate.
var mainPredicate = PredicateBuilder.True<Document>();
// ... some other conditions to the main predicate here ...
// The inner predicate (combined conditions using OR).
var innerPredicate = PredicateBuilder.False<Document>();
foreach (var period in periods)
{
var p = period;
innerPredicate =
innerPredicate.Or(
d =>
(d.Date >= p.DateFrom && d.Date <= p.DateTo));
}
mainPredicate = mainPredicate.And(innerPredicate);
documents = this.ObjectSet.AsExpandable().Where(mainPredicate).ToList();
I am combining my two predicates just like it is explained in the documentation. However, I get this exception :
The parameter 'f' was not bound in the specified LINQ to Entities
query expression
I first thought that the inner predicate has to be expanded before combining it with the main predicate, so I changed my combining code to add a call to to the inner predicate's Expand method like this :
mainPredicate = mainPredicate.And(innerPredicate.Expand());
But I get the exact same exception.
The only difference in my code versus the documentation is that I dynamically build my nested predicate using a foreach loop. I just don't know how it can negatively affect the resulting expression.
What is wrong with my code ?
How can I actually debug this ?
Where the f parameter comes from ? How is it generated ? Why is it problematic in my case ?
Is there some kind of expression tree visualizer of some kind that could help me actually see what is wrong with the resulting expression ? Because the expression's body is hard to read.
Finally, I have found a way to avoid combining multiple predicates to the main expression tree.
Given that each predicate represents a different filter and I want the final, combined filter to be a series of must-be-respected conditions, we can say that each of the predicates has to return true for the final predicate to return true.
For that to work, the predicates has to be combined with AND. So, the resulting SQL query must look like this :
predicate1 AND predicate2 AND predicate3 ...
A better way to combine these predicates with AND is to chain Where query operators to the final query, like this :
var documents = this.ObjectSet.AsExpandable()
.Where(mainPredicate)
.Where(otherPredicate)
.Where(yetAnotherPredicate)
.ToList();
The resulting SQL query will combine each of these predicates with AND. That is just what I wanted to do.
It is easier than hacking out an expression tree by myself.

Linq2SQL "or/and" operators (ANDed / ORed conditions)

Let's say we need to apply several conditions to select from a table called "Things" (unknown count and nature)
if conditions are known, we can write
db.Things.Where(t=>foo1 && foo2 || foo3);
but if we have to build that Where condition programatically, I can imagine how can we apply ANDed conditions
IQuerable DesiredThings = db.Things.AsQuerable();
foreach (Condition c in AndedConditions)
DesiredThings = DesiredThings.Where(t => GenerateCondition(c,t));
What about ORed conditions ?
Note: we don't want to perform union, unique, or any other costly operations, it's desired that a query is generated as if we write it ad-hock
Thanks in advance.
Addition:
PredicateBuilder: Dynamically Composing Expression Predicates
You could use the Expression class with static methods to do it run time.
The below code is ment to create a delegate taking one argument called value of type int
. It reads from buttom to top so the line in question is:
var method = LambdaExpression.Lambda(orExp, Expression.Parameter(typeof(int), "value"));
the body of the method compares the value of the parameter to a call to method Bar of a newly created object of type foo
var exp2 = Expression.Equal(Expression.Parameter(typeof(int), "value"), Expression.Property(Expression.New(typeof(Foo).GetConstructor(new Type[] { })), "Bar"));
It then creates a similar expression and or's them
var orExp = Expression.OrElse(exp1, exp2);
final thing is the call to compile. That call generates a delegate that can be used in your where method call.
hope it helps tho Im not 100% sure on the expression to get the value from a parameter
var exp1 = Expression.Equal(Expression.Parameter(typeof(int),"value"), Expression.Property(Expression.New(typeof(Bar).GetConstructor(new Type[] { })), "Foo"));
var exp2 = Expression.Equal(Expression.Parameter(typeof(int), "value"), Expression.Property(Expression.New(typeof(Foo).GetConstructor(new Type[] { })), "Bar"));
var orExp = Expression.OrElse(exp1, exp2);
var method = LambdaExpression.Lambda(orExp, Expression.Parameter(typeof(int), "value"));
method.Compile();
You might wanna look at invoke for invokation instead of compiling the expression, if you need the LambdaExpression to be translated into something different than binary code (E.g. into an SQL statement)
For OR, you have two choices:
use Union/Concat
write the Expression in code
The second is closer to the .Where(x => {a} || {b}).
If you are using LINQ-to-SQL, you can use Expression.Invoke to combine multiple separate lambda expressions (see this answer) - however, this isn't supported in Entity Framework. In EF, you have to build the entire expression as a single block, using Expression.OrElse; for example here or here.

Categories

Resources