1

i want to replace operator(==, >= ,>...) in the clause where of linq lambda with parameter passed in method

the 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 the clause where with the parameter filter to obtain something like this

     var mod = from o in new GpsContext().Locals.Where(loc => loc.Date filter dt)

any body knows how to make it work ?

5 Answers 5

3

I think it's better to make dictionary out 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));

        ...
     }
}
Sign up to request clarification or add additional context in comments.

Comments

1

There is a good library for parsing strings into Lamdba expressions described here

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

and downloadable here

http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx

It has a pretty good expression syntax that lets you express quite a lot of different queries and operations.

Be aware though that depending on the query, you may lose some type safety. Where operations are OK, but any kind of projection where the Select lambda is parsed from a string cannot be inferred by the compiler. This measn you end up with non-generic IQueryables rather than generically typed ones. Sometimes this is OK, but it does prevent you from using generic extension methods later on in the query.

Edit to clarify situation with non-generic query operations: The library contains a set of non-generic versions of the query extension methods that take string representations of expressions and operate on non-generic IQueryable. If you look at the code, it is pretty easy to see how to write these if the one you want isn't there. For example, I needed to do a non-generic Join and it only took a couple of hours.

Comments

1

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 than, greater than, etc. and it will get translated 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 });
        }
    }
}

Comments

0

You could pass in the function that is your where clause, e.g.

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));

1 Comment

Of course in this scenario there is little point in extracting this functionality to a method, as the date parsing part would need to be run before you call the method and used as part of the method call (SomeDate in my example)
-1

And the filter should contain "==", ">=" etc? You can analyse filter string in a traditional way:

var mod = from o in new GpsContext().Locals.Where(loc => 
{
    switch(filter)
    {
        case "==":
            return loc.Date == dt;
        case ">=":
            return loc.Date >= dt;
        // ...
    }
})

1 Comment

@ElDog the problem that i have many filters --> many where clauses. that's why i don't prefer this way

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.