Retrieve value of lambda expression - linq

I have this function:
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> exp1, Expression<Func<TSource, bool>> exp2, Expression<Func<TSource, bool>> exp3)
{
}
and i use the function like this :
adverts.WhereIf(x=>x.DeactivatedDate.HasValue, x => x.DeactivatedDate.Value > starDateTime, x => x.ModifiedDate > starDateTime);
How can i get the value of exp1 ?

In the extenssion i need to know if DeactivatedDate.HasValue is true
You can evaluate the expression, but you need an instance of TSource to evaluate against. Since your "input" is a collection of TSource youe solution might be something like:
foreach(TSource t in source)
{
bool isTrue = exp1.Compile()(t); // evaluate exp1 for this item
if(isTrue)
// do something
else
// do something else
}
but note that your return type in an IQueryable<TSource> - so I'm not sure you've fully thought through how you intend to build up the resulting query...

Related

How to write condition based on expression?

I am trying to write condition based on expression.
I have two classes Test1 and Test2.
public class Test1<TEntity, TProperty>
{
public IQueryable<TEntity> Test(
IQueryable<TEntity> queryable,
Expression<Func<TEntity, TProperty>> expression,
TProperty value
)
{
MemberExpression memberExpression = (MemberExpression)(expression.Body);
var propName = memberExpression.Member.Name;
// Cannot apply operator '>' to operands of type 'P' and 'P'
queryable = queryable.Where(e => EF.Property<TProperty>(e, propName) > value));
return queryable;
}
}
public class Test2<TEntity, TProperty>
where TProperty : IComparable
{
public IQueryable<TEntity> Test(
IQueryable<TEntity> queryable,
Expression<Func<TEntity, TProperty>> expression,
TProperty value
)
{
MemberExpression memberExpression = (MemberExpression)(expression.Body);
var propName = memberExpression.Member.Name;
// This one compiles
queryable = queryable.Where(e => EF.Property<TProperty>(e, propName).CompareTo(value) > 0);
return queryable;
}
}
First one (Test1) tries to compare values with > but it does not compile. Second one (Test2) declares generic type as IComparable and uses .CompareTo() method inside where condition. This one compiles but on runtime it throws:
The LINQ expression 'DbSet<SortableEntity>
.Where(s => s.IsDeleted == False)
.Where(s => EF.Property<long>((object)s, "Id").CompareTo((object)__value_0) > 0)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()
Is it possible to somehow write custom condition based on expression? I want property/member expression to be passed by user and then decide what condition to apply to IQueryable.
Well, EF.Property is last thing that you have to use in such situation. You have property, even correct body - use this:
public class Test1<TEntity, TProperty>
{
public IQueryable<TEntity> Test(
IQueryable<TEntity> queryable,
Expression<Func<TEntity, TProperty>> expression,
TProperty value
)
{
var predicateLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.GreaterThan(expression.Body, Expression.Constant(value, typeof(TProperty))),
expression.Parameters[0]);
queryable = queryable.Where(predicateLambda);
return queryable;
}
}

Bad result using query generated automatically with predicate and OR condition

I use this predicate with EF and lamdba expression :
public class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
}
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
}
Now I just want to dynamically build this query :
Query(ufe => (ufe.FilmEtat.filmetat_code == etatString && ufe.user_id == 2) || (ufe.FilmEtat.filmetat_code == etatString && ufe.user_id == 11)).ToList();
I already tried :
var predicate = PredicateBuilder.True<UtilisateurFilmEtat>();
int i = 0;
foreach (int utilisateurId in listUtilisateurId)
{
if (i == 0)
predicate = ufe => (ufe.FilmEtat.filmetat_code == etatString && ufe.user_id == utilisateurId);
else
predicate.Or(ufe => ufe.FilmEtat.filmetat_code == etatString && ufe.user_id == utilisateurId);
i++;
}
The query is working but not return the good results...
I am becoming crazy :(
Need your help.
Thank you
Your question seems very similar to this one: Linq to SQL how to do "where [column] in (list of values)", although not an exact duplicate.
I can see that you're trying to dynamically build a query by combining other querys with ||, which is what you'd want to do if you only had a comparison operator...
Instead, how about something like this: ufe => listUtilisateurId.Contains(ufe.user_id)

How to use Expression for Linq union and intersect?

I have code
public static class PredicateExtensions
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
{
var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression), expression1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
{
var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
}
}
How to use this code instead of LINQ Union and Intersect methods ?
If you have a union and intersection of the form:
var union = source.Where(predicate0).Union(source.Where(predicate1));
var inter = source.Where(predicate0).Intersect(source.Where(predicate1));
Then union will have the values for which either predicate0 or predicate1 was true while inter will have the values for which both predicate0 and predicate1 were true.
For this reason, the following would have the same result:
var union = source.Where(predicate0.Or(predicate1));
var inter = source.Where(predicate0.And(predicate1));
This depends upon the components of the union and intersection being produced by two Where queries though. In the likes of:
var union = source1.Where(predicate0).Select(item => item.ID)
.Union(source2.Where(predicate1).Select(item => item.ID));
Then it's likely that the predicates aren't even of the same type, and there are yet other cases where combining predicates will not work as a replacement of Union and Intersect.
It is though useful to be able to consider the first examples both ways, in terms of one's understanding of how predicates, unions and intersections work.

Building a lambda WHERE expression to pass into a method

I need to pass in a "where" lambda expression that'll be used in a LINQ query inside a method. The problem is, I don't know what the where value will be compared against until I get into the method.
Now to explain further and clarify some of what I said above I'll come up with a bit of a contrived example.
Imagine I have a List<Products> and I need to narrow that list down to a single record using a productId property of the Products object. Normally I would do this:
var product = productList.Where(p=>p.productId == 123).FirstOrDefault();
Now take it a step further - I need to put the above logic into a method that isn't limited to a List<Products> but is instead a List<T> so ideally, I'd be calling it like this (and I know the below won't work, it's simply here to show what I am trying to achieve):
myMethod(productList, p => p.productId == X)
With the caveat being that X isn't known until I'm inside the method.
Finally, for what it's worth, I need to point out that my collection of data is an OData DataServiceQuery.
So, to re-summarize my question: I need to know how to construct a lambda "where" expression that I can pass into a method and how to use it against a collection of objects in a LINQ query.
myMethod(productList, p => p.productId == X) - you can emulate with this trick
static void myMethod<T>(List<T> list, Func<T,bool> predicate, ref int x)
{
x = 5;
var v = list.Where(predicate);
foreach (var i in v)
Console.Write(i);
Console.ReadLine();
}
static void Main(string[] args)
{
List<int> x = new List<int> { 1, 2, 3, 4, 5 };
int z = 0;
myMethod(x, p => p == z, ref z);
}
but not sure if it solves your problem in whole
For one, if you are going to query an IEnumerable<T>, you will need to ensure that your comparison will work in the first place. In that case you can make your objects implement an interface that guarantees that they will support the comparison.
Once you do that, your method can have a generic constraint that limits the input to those interfaces. At that point, your method can take a Func, which can be passed to the LINQ Where clause:
public interface Identifier
{
int Id { get; set; }
}
public class Product : Identifier
{
public int Id { get; set; }
//Other stuff
}
public T GetMatch<T>(IEnumerable<T> collection, Func<T, int, bool> predicate) where T : Identifier
{
int comparison = 5;
return collection.Where(item => predicate(item, comparison)).FirstOrDefault();
}
Which can be invoked like:
var match = GetMatch<Identifier>(collection, (x, y) => x.Id == y);
UPDATE:
I modified the above code to take in a comparison parameter
You could try to use the PredicateBuilder class from the free LinqKit library(tutorial).
You can then construct a predicate using
PredicateBuilder predicate = PredicateBuilder.True<T>();
predicate = PredicateBuilder.And(predicate, p=> p.product_id == X);
where X is of type T.
You can use this predicate in a where clause such as .Where(predicate) and return an IQueryable or return the predicate itself which would be of type Expression<Func<T, bool>>

If statements within a Linq where clause

Struggling a bit today.
I have the following method that returns a list of products..lovely.
public static List<tblWeight> GetProductInfo(string memberid, string locationid, string basematerial, string source)
{
MyEntities getproductinfo = new MyEntities ();
return (from p in getproductinfo .tblWeights
where p.MemberId == memberid &&
p.LocationId == locationid &&
p.BaseMaterialName == basematerial &&
p.WeightStatus == source
select p)
.ToList();
Where basematerial & source are drop down lists.
How do I go about incorporating a few IF statements into the where clause?
For example, if the basematerial ddl is not touched but an item in the source ddl is selected, the result would return everything associated with basematerial but filtered by the selected source.
Does that even make sense?!
I'm not even sure I am taking the correct approach - please forgive my ignorance.
you can add them to your query on need:
var r = (from p in getproductinfo .tblWeights
where p.MemberId == memberid &&
p.LocationId == locationid &&
p.WeightStatus == source
select p)
if (!String.IsNullOrEmpty(basematrial))
r = r.Where(p => p.BaseMaterialName == basematerial);
return r.ToList();
Consider implementing these extension methods named WhereIf.
You pass it two parameters: a statement evaluated to a boolean, and a lambda function. If the bool statement evaluates to true, the lambda is added.
WhereIf on ExtensionMethod.net
Your query could look like:
return getproductinfo.tblWeights
.Where(w=> w.MemberId == memberid &&
w.LocationId == locationid)
.WhereIf(!string.IsNullOrEmpty(basematerial), w=>w.BaseMaterialName == basematerial)
.WhereIf(!string.IsNullOrEmpty(source), w=>w.WeightStatus == source)
.ToList();
Here they are, for both IEnumerable and IQueryable. This allows you to use .WhereIf() in LINQ To SQL, Entity Framework, Lists, Arrays, and anything else that implements those 2 interfaces.
public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, bool condition, Func<TSource, bool> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, bool condition, Func<TSource, int, bool> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Func<TSource, bool> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Func<TSource, int, bool> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}

Resources