замена оператора в предложении Where лямбда параметром - PullRequest
1 голос
/ 09 февраля 2012

Я хочу заменить оператор (==,> =,> ...) в предложении, где linq лямбда с параметром, переданным в методе

метод:

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)

я хочу заменить == в предложении где с параметром filter, чтобы получить что-то вроде этого

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

любой орган знает, как заставить его работать?

Ответы [ 5 ]

3 голосов
/ 09 февраля 2012

Я думаю, что лучше сделать словарь из строковых фильтров и соответствующих делегатов.

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

        ...
     }
}
1 голос
/ 09 февраля 2012

Я нашел решение вашей проблемы, которое работает следующим образом:

var test = dataContext.Interactions.DynamicWhere<Interaction,DateTime>("Created_Month", ExpressionType.LessThan, DateTime.Now);

Вы можете использовать любое значение ExpressionType - равно, меньше, больше и т. Д., И оно будет переведено на T-SQL, если это возможно (поэтому фильтрация будет выполняться на сервере).Он также будет работать в памяти на IEnumerables.

Вот код:

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 });
        }
    }
}
1 голос
/ 09 февраля 2012

Существует хорошая библиотека для разбора строк в выражениях Lamdba, описанная здесь

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

и можно загрузить здесь

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

Он имеет довольно хороший синтаксис выражений, который позволяет вам выражать довольно много различных запросов и операций.

Имейте в виду, что в зависимости от запроса вы можете потерять некоторый тип безопасности. Там, где операции в порядке, но любой вид проекции, в котором лямбда-выражение Select анализируется из строки, не может быть выведен компилятором. Это означает, что в итоге вы получите неуниверсальные IQueryables, а не типизированные. Иногда это нормально, но это не позволяет вам использовать общие методы расширения позже в запросе.

Редактировать, чтобы прояснить ситуацию с неуниверсальными операциями запроса : Библиотека содержит набор неуниверсальных версий методов расширения запроса, которые принимают строковые представления выражений и оперируют с неуниверсальным IQueryable. Если вы посмотрите на код, то довольно легко увидеть, как его написать, если нужного вам там нет. Например, мне нужно было сделать неуниверсальное соединение, и это заняло всего пару часов.

0 голосов
/ 09 февраля 2012

Вы можете передать функцию, которая является вашим предложением where, например,

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

И вызвать ее с помощью:

GetByFiltre(f => f.Where(d => d.Date > SomeDate));
0 голосов
/ 09 февраля 2012

А фильтр должен содержать "==", "> =" и т. Д.?Вы можете проанализировать строку фильтра традиционным способом:

var mod = from o in new GpsContext().Locals.Where(loc => 
{
    switch(filter)
    {
        case "==":
            return loc.Date == dt;
        case ">=":
            return loc.Date >= dt;
        // ...
    }
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...