I have been searching a lot about my current problem but I could not find a real answer to solve that issue.
I am trying to build a LINQ Query that produces the followi
If you want to build your query programmatically and have it execute on your SQL server instead of fetching all records and querying in memory, you need to use the set of static methods on the Expression
class and build your query using those. In your example:
public class Query // this will contain your 20 fields you want to check against
{
public int? Field1; public int? Field2; public int? Field3; public int Field4;
}
public class QueriedObject // this is the object representing the database table you're querying
{
public int QueriedField;
}
public class Program
{
public static void Main()
{
var queryable = new List<QueriedObject>().AsQueryable();
var query = new Query { Field2 = 1, Field3 = 4, Field4 = 2 };
// this represents the argument to your lambda expression
var parameter = Expression.Parameter(typeof(QueriedObject), "qo");
// this is the "qo.QueriedField" part of the resulting expression - we'll use it several times later
var memberAccess = Expression.Field(parameter, "QueriedField");
// start with a 1 == 1 comparison for easier building -
// you can just add further &&s to it without checking if it's the first in the chain
var expr = Expression.Equal(Expression.Constant(1), Expression.Constant(1));
// doesn't trigger, so you still have 1 == 1
if (query.Field1.HasValue)
{
expr = Expression.AndAlso(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field1.Value)));
}
// 1 == 1 && qo.QueriedField == 1
if (query.Field2.HasValue)
{
expr = Expression.AndAlso(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field2.Value)));
}
// 1 == 1 && qo.QueriedField == 1 && qo.QueriedField == 4
if (query.Field3.HasValue)
{
expr = Expression.AndAlso(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field3.Value)));
}
// (1 == 1 && qo.QueriedField == 1 && qo.QueriedField == 4) || qo.QueriedField == 2
expr = Expression.OrElse(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field4)));
// now, we combine the lambda body with the parameter to create a lambda expression, which can be cast to Expression<Func<X, bool>>
var lambda = (Expression<Func<QueriedObject, bool>>) Expression.Lambda(expr, parameter);
// you can now do this, and the Where will be translated to an SQL query just as if you've written the expression manually
var result = queryable.Where(lambda);
}
}
Ok you have had your own share of answer about linq.
Let me introduce a different approach using Dynamic.linq
// You could build a Where string that can be converted to linq.
// and do if sats and append your where sats string. as the example below
var query = "c => (c.Field1 == \" a \" && c.Field2 == Y) || (c.Field3 == \" b \")";
var indicator = query.Split('.').First(); // the indicator eg c
// assume TABLE is the name of the class
var p = Expression.Parameter(typeof(TABLE), indicator);
var e = DynamicExpression.ParseLambda(new[] { p }, null, query);
// and simple execute the expression
var items = Object.Where(e);
You can use Expression
to create in one step like this:
Expression<Func<Model, bool>> exp = (model =>
((model.Field1.HasValue && c.Field1 == X) &&
(model.Field2.HasValue && c.Field2 == X)) ||
model.Field3 == X
)
Once you have your predicates defined, it's very easy to use them in a query.
var result = Query.AsQueryable().Where(exp)
Check the code in this gist: my gist url
UPDATE 1: If You have to use steps to create your expression you can use this:
Expression<Func<Model, bool>> exp = c => true;
if (model.Field1.HasValue)
{
var prefix = exp.Compile();
exp = c => prefix(c) && c.Field1 == X;
}
if (model.Field2.HasValue)
{
var prefix = exp.Compile();
exp = c => prefix(c) && c.Field2 == X;
}
[...] like 20 more of these .Where() calls.
First, create some helper extension methods to easier combine two Func<T,bool>
predicates:
public static Func<T, bool> And<T>(this Func<T, bool> left, Func<T, bool> right)
=> a => left(a) && right(a);
public static Func<T, bool> Or<T>(this Func<T, bool> left, Func<T, bool> right)
=> a => left(a) || right(a);
Then you can use them to chain predicates:
var list = Enumerable.Range(1, 100);
Func<int, bool> predicate = v => true; // start with true since we chain ANDs first
predicate = predicate.And(v => v % 2 == 0); // numbers dividable by 2
predicate = predicate.And(v => v % 3 == 0); // numbers dividable by 3
predicate = predicate.Or(v => v % 31 == 0); // numbers dividable by 31
var result = list.Where(predicate);
foreach (var i in result)
Console.WriteLine(i);
Output:
6
12
18
24
30
31
36
42
48
54
60
62
66
72
78
84
90
93
96