I have this code :
var listExpression = new List<Expression>();
var parameter = Expression.Parameter(typeof(T));
var memberExpression = Expression.PropertyOrField(parameter, MyProperty);
listExpression.Add(
Expression.Call(
((MemberExpression)memberExpression), "Contains", null,
Expression.Constant((string)MyValue))
);
Expression body = Expression.Constant(true);
foreach (var expression in listExpression)
body = Expression.And(body, expression);
return Expression.Lambda<Func<T, bool>>(body, parameter);
The result of this is :
"True & $var1.AGE >= 5"
I don't have any problem when I use this predicate with Entity Framework but not work with NHiernate. I think the problem is the "True". Is it possible to create this predicate without this "True" ?
replace
Expression body = Expression.Constant(true);
foreach (var expression in listExpression)
body = Expression.And(body, expression);
by
var body = listExpression.First();//check first if listExpression.Any() would be better
listExpression.Skip(1).Aggregate(body, Expression.And);
Related
I have an object called SearchDetails which contains:
SearchDetails:
{ ColName: "StrName"
SearchVal" "mega" }
I am making a generic lambda expression by using reflection method.
public dynamic searchMethod(object SearchDetails)
{
ParameterExpression Parameter = Expression.Parameter(typeof(SearchDetails), "x");
var searchCol = Expression.Property(
Parameter,
SearchDetails.GetType().GetProperty("ColName")
);
var colVal = Expression.Property(
Parameter,
SearchDetails.GetType().GetProperty("SearchValue").Name
);
Expression contMethod = Expression.Call(searchCol, "Contains", null, colVal);
Expression<Func<SearchDetails, bool>> lambda =
Expression.Lambda<Func<SearchDetails, bool>>(contMethod, Parameter);
return lambda;
}
The problem is that I am getting lambda expressions as follow:
{x => x.ColName.Contains(x.SearchValue)}
However, I want it to be like this: {x => x.StrName.Contains("megabrand")}.
I cannot access the value of the properties: ColName and SearchValue.
How to solve this problem?
What you are looking for is probably something similar to this:
public static Expression<Func<TSource, bool>> SearchMethod<TSource>(SearchDetails searchDetails)
{
ParameterExpression par = Expression.Parameter(typeof(TSource), "x");
var col = Expression.Property(par, searchDetails.ColName);
Expression body = Expression.Call(col, "Contains", null, Expression.Constant(searchDetails.SearchVal));
var lambda = Expression.Lambda<Func<TSource, bool>>(body, par);
return lambda;
}
Note that you have to pass the type of your table somewhere, in this case as a generic parameter TSource.
Use it like:
var search = new SearchDetails
{
ColName = "Foo",
SearchVal = "Bar",
};
var lambda = SearchMethod<TbStore>(search);
As an alternative you could use System.Linq.Dynamic.Core to obtain something similar.
var result = db.Where(searchDetails.ColName + ".Contains(#0)", searchDetails.SearchVal);
I have similar Situation like here: How to declare a Linq Expression variable in order to have it processed as a dbParameter
But in my case, don't want to compare with 'equal' operator, I need to compare one string against another. How can I achieve this?
I tried something like this:
var comparsionString = "aaa";
ParameterExpression param = Expression.Parameter(typeof(ItemSearch), "s");
Expression prop = Expression.Property(param, "Id");
Expression<Func<string>> idLambda = () => comparsionString;
Expression searchExpr = Expression.GreaterThanOrEqual(prop, idLambda.Body);
Expression<Func<ItemSearch, bool>> myLambda =
Expression.Lambda<Func<ItemSearch, bool>>(searchExpr, param);
But unfortunately GreaterThanOrEqual is not supported for strings. So I would need the string.CompareTo(..) method which is supported at least by SQL to Entities.
Say:
Expression searchExpr = Expression.IsTrue(*prop*.CompareTo(*idLambda*) >= 0);
How to write this in a way, that compiler can understand?
Any help is apreciated.
Thank you!
If you investigate the compiler translation for
Expression<Func<string, bool>> f = s => s.CompareTo("aaaa") >= 0;
You will discover you need to use GreaterThanOrEqual(Call("s", "CompareTo", "aaaa")) so the code to create that is:
var comparsionString = "aaa";
ParameterExpression param = Expression.Parameter(typeof(ItemSearch), "s");
Expression prop = Expression.Property(param, "Id");
Expression<Func<string>> idLambda = () => comparsionString;
var CallMethod = typeof(string).GetMethod("CompareTo", new[] { typeof(string) });
Expression callExpr = Expression.Call(prop, CallMethod, idLambda.Body);
Expression searchExpr = Expression.GreaterThanOrEqual(callExpr, Expression.Constant(0));
Expression<Func<ItemSearch, bool>> myLambda =
Expression.Lambda<Func<ItemSearch, bool>>(searchExpr, param);
When ToList is applied always this exception is thrown
Value cannot be null. Parameter name: querySource
var memberExpression = (navigationPropertyPath.Body as MemberExpression);
var returnType = memberExpression.Member is MethodInfo? ((MethodInfo)memberExpression.Member).ReturnType: ((PropertyInfo)memberExpression.Member).PropertyType;
var parameter = Expression.Parameter(typeof(TEntity), "s");
var fieldParameter = Expression.Parameter(returnType.GetTypeInfo().GetGenericArguments()[0], "field");
var anyPredicate = Expression.Lambda(
Expression.NotEqual(
Expression.PropertyOrField(fieldParameter, "Column"),
Expression.Constant(true)
),
fieldParameter);
var fieldCondition = Expression.Call(
typeof(Enumerable).GetMethods().Where(x=>x.Name == "Any").Skip(1).Take(1).First().MakeGenericMethod(new[] { fieldParameter.Type }),
memberExpression,
anyPredicate);
// You can use the fieldCondition in your combinator,
// the following is just to complete the example
var predicate = Expression.Lambda<Func<TEntity, bool>>(fieldCondition, parameter);
var list= source.Where(predicate).ToList(); ;
This code creates a custom standard WHERE query and tries to convert the result to a list.
Does anyone know how to fix this?
I'm making a lambda expression like this :
var property = typeof(Customer).GetProperty(inputArray[0], BindingFlags.Instance | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(Customer));
var memberExpression = Expression.Property(parameter, property);
var eq = Expression.Equal(memberExpression, Expression.Constant(value));
//Combining eq with ANDs and ORs
var lambdaExpression = Expression.Lambda<Func<Customer, bool>>(eq, parameter);
// the lambda expression looks like this : {Param_0 => ((Param_0.NAME== "JASON") And (Param_0.NAME == "JASON"))}
var filteredCustomers = db.Customer.Where(lambdaExpression);
var list = filteredCustomers.ToList();
I can see that there are records whose name is JASON in the db. But list count is always zero. Can you tell me what the problem is? Thanks in advance.
For future visitors looking at this post,OP has trimmed the value removing extra spaces.
var param = Expression.Parameter(typeof(Customer), "p");
var memberExpression = Expression.PropertyOrField(param, "Your_Property_Name");
var body = Expression.Equal(memberExpression, Expression.Constant(value.Trim()));
var lambda = Expression.Lambda(body, param);
I use the code gave on Stackoverflow by Marc Gravell here :
http://goo.gl/57nW2
The code :
var param = Expression.Parameter(typeof (Foo));
var pred = Expression.Lambda<Func<Foo, bool>>(
Expression.Call(
Expression.PropertyOrField(param, fieldName),
"StartsWith",null,
Expression.Constant(stringToSearch)), param);
Now, I'd like combine several argument, sample :
public void BuildPredicate(string[] typeSearch, string[] field, string searchValue)
{
//Content
//typeSearch = new string[] {"Contains", "StartsWith", "StartsWith" };
//field = new string[] { "FieldA", "FieldB", "FieldC" };
//FieldA contains searchValue and FieldB startWith searchValue and FieldC startWith searchValue
}
An idea ?
Thanks,
You can simply loop over all operations on all fields and build up a Expression tree containing an OrElse clause for each type/field combination
var expressions = from type in typeSearch
from field in fields
select Expression.Call(
Expression.PropertyOrField(param, field),
type, null,
Expression.Constant(stringToSearch));
Expression body = Expression.Constant(false);
foreach (Expression expression in expressions)
{
body = Expression.OrElse(body, expression);
}
var result = Expression.Lambda<Func<Foo, bool>>(body, param);
And as requested, an example including calls to ToUpper:
var expressions = from type in typeSearch
from field in fields
select Expression.Call(
Expression.Call(
Expression.PropertyOrField(param, field),
"ToUpper", null),
type, null,
Expression.Constant(stringToSearch));