Replace Operator in Where Lambda Section with Parameter
I want to replace operator (==,> =,> ...) in the where clause of linq lambda with a parameter passed in the method
method:
public IEnumerable<Localisation> GetByFiltre(string filter, string valeurDate1)
/*
filter has the value of an operator:
>
==
!=
>=
<=
*/
DateTime dt = Convert.ToDateTime(valeurDate1);
var mod = from o in new GpsContext().Locals.Where(loc => loc.Date == dt)
I want to replace == in a sentence where with a parameter filter get something like this
var mod = from o in new GpsContext().Locals.Where(loc => loc.Date filter dt)
does any body know how to make it work?
source to share
I think it is better to make a dictionary of string filters and corresponding delegates.
class YourClass
{
static readonly Dictionary<string, Func<DateTime, DateTime, bool>> s_filters = new Dictionary<string, Func<DateTime, DateTime, bool>>
{
{ ">", new Func<DateTime, DateTime, bool>((d1, d2) => d1 > d2) }
{ "==", new Func<DateTime, DateTime, bool>((d1, d2) => d1 == d2) }
{ "!=", new Func<DateTime, DateTime, bool>((d1, d2) => d1 != d2) }
{ ">=", new Func<DateTime, DateTime, bool>((d1, d2) => d1 >= d2) }
{ "<=", new Func<DateTime, DateTime, bool>((d1, d2) => d1 <= d2) }
};
public IEnumerable<Localisation> GetByFiltre(string filter, string valeurDate1)
{
...
DateTime dt = Convert.ToDateTime(valeurDate1);
var filterDelegate = s_filters[filter];
var mod = from o in new GpsContext().Locals.Where(loc => filterDelegate(loc.Date,dt));
...
}
}
source to share
There is a good library for parsing strings in Lamdba expressions described here.
and downloadable here
http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx
It has pretty good expression syntax that allows you to express quite a few different queries and operations.
Remember, depending on the request, you may lose some security. In cases where the operations are ok, but any projector where the lambda selection is parsed from a string cannot be output by the compiler. This means that you end up with not generic IQueryables and not typically typed ones. Sometimes this is fine, but it prevents you from using generic extension methods later in the request.
Edit to clarify things with non-generic queries. ... The library contains a set of non-generic versions of query extension methods that accept string representations of expressions and operate on an unequal IQueryable. If you look at the code, it's pretty easy to see how to write them if the one you want doesn't exist. For example, I needed to make a non-general video, and it only took a couple of hours.
source to share
I found a solution to your problem that works like this:
var test = dataContext.Interactions.DynamicWhere<Interaction,DateTime>("Created_Month", ExpressionType.LessThan, DateTime.Now);
You can use any ExpressionType
- equals, less, more, etc., and it will translate to T-SQL if possible (so the filtering will be done on the server). It will also work in memory on IEnumerables
.
Here's the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace WindowsFormsApplication1
{
public static class GenericFilterExtension
{
public static IQueryable<TRow> DynamicWhere<TRow,TColumn>(this IQueryable<TRow> input, string field, ExpressionType binaryOperator, TColumn value)
{
var exp = MakeWhereLambda<TRow, TColumn>(field, binaryOperator, value) as Expression<Func<TRow, bool>>;
return input.Where(exp);
}
public static IEnumerable<TRow> DynamicWhere<TRow, TColumn>(this IEnumerable<TRow> input, string field, ExpressionType binaryOperator, TColumn value)
{
var exp = MakeWhereLambda<TRow, TColumn>(field, binaryOperator, value).Compile() as Func<TRow, bool>;
return input.Where(exp);
}
private static LambdaExpression MakeWhereLambda<TRow, TColumn>(string field, ExpressionType binaryOperator, TColumn value)
{
var param = Expression.Parameter(typeof(TRow), "n");
var op = Expression.MakeBinary(binaryOperator, Expression.Property(param, field), Expression.Constant(value));
return Expression.Lambda(op, new ParameterExpression[] { param });
}
}
}
source to share
You can pass a function that is a where clause, for example.
public IEnumerable<Localisation> GetByFiltre(Func<IEnumerable<localisation>, IEnumerable<localisation>> whereClause)
{
/*
filter has the value of an operator:
>
==
!=
>=
<=
*/
DateTime dt = Convert.ToDateTime(valeurDate1);
var mod = whereClause(new GpsContext().Locals);
}
And call it with:
GetByFiltre(f => f.Where(d => d.Date > SomeDate));
source to share