Многоразовый установщик предикатов DateTime PredicateBuilder

Я использую PredicateBuilder для создания предложений динамического поиска. В приведенном ниже примере кода можно ли изменить SetDateTimePredicate, чтобы его можно было использовать для любого свойства DateTime в SomeType?

Expression<Func<SomeType, bool>> somePredicate = null;
somePredicate = somePredicate.Or(
    SetDateTimePredicate(comparisonOperator, dateTime1, dateTime2));

private Expression<Func<SomeType, bool>> SetDateTimePredicate(
    Enums.ComparisonOperator comparison,
    DateTime dateTime1,
    DateTime dateTime2)
{
    switch (comparison)
    {
        case Enums.ComparisonOperator.IsLessThan:
            return p => p.SomeDateProperty < dateTime1;
        case Enums.ComparisonOperator.IsLessThanOrEqualTo:
            return p => p.SomeDateProperty <= dateTime1;
        case Enums.ComparisonOperator.IsGreaterThan:
            return p => p.SomeDateProperty  > dateTime1;
        case Enums.ComparisonOperator.IsGreaterThanOrEqualTo:
            return p => p.SomeDateProperty >= dateTime1;
        case Enums.ComparisonOperator.IsBetween:
            return p => p.SomeDateProperty >= dateTime1 
                     && p.SomeDateProperty <= dateTime2;
        default:
            return p => p.SomeDateProperty == dateTime1;
    }
}

Я попробовал метод расширения, но получил эту ошибку:

System.NotSupportedException occurred
Message="Method 'Boolean Compare(System.DateTime, ComparisonOperator, System.DateTime, System.DateTime)' has no supported translation to SQL."    

Метод расширения:

public static bool Compare(
    this DateTime dateToCompare,
    Enums.ComparisonOperator comparison,
    DateTime dateTime1,
    DateTime dateTime2)
{
    switch (comparison)
    {
        case Enums.ComparisonOperator.IsLessThan:
            return dateToCompare < dateTime1;
        case Enums.ComparisonOperator.IsLessThanOrEqualTo:
            return dateToCompare <= dateTime1;
        case Enums.ComparisonOperator.IsGreaterThan:
            return dateToCompare > dateTime1;
        case Enums.ComparisonOperator.IsGreaterThanOrEqualTo:
            return dateToCompare >= dateTime1;
        case Enums.ComparisonOperator.IsBetween:
            return dateToCompare >= dateTime1
                && dateToCompare <= dateTime2;
        default:
            return dateToCompare == dateTime1;
    }
}

Пример с методом расширения:

somePredicate = somePredicate.Or(
    p => p.SomeDateProperty.Compare(comparisonOperator, dateTime1, dateTime2));

person user1360192    schedule 27.04.2012    source источник
comment
Я проверил первый способ, и он сработал. Можете ли вы опубликовать больше контекста?   -  person Adrian Iftode    schedule 27.04.2012
comment
Да, у меня тоже работает метод SetDateTimePredicate. Я хочу изменить его так, чтобы он принимал любое свойство DateTime в моем типе (и не был жестко закодирован для SomeDateProperty). Или, если есть другой способ сделать то же самое, это тоже было бы хорошо. Я попробовал метод расширения, но получил ошибку, о которой я упоминал.   -  person user1360192    schedule 27.04.2012


Ответы (1)


Ниже приведено общее решение, которое можно использовать для любого типа, в котором определены операторы сравнения, а не только DateTime. Я сделал методы, методы расширения на типе Enum.ComparisionOperator. Он будет использоваться как:

Expression<Func<SomeType, bool>> somePredicate = comparisonOperator.Compare(
    (SomeType p) => p.SomeDateProperty, dateTime1, dateTime2));

Методы, определенные как:

public static Expression<Func<TSource, bool>> Compare<TSource, TValue>(
    this Enums.ComparisonOperator comparison,
    Expression<Func<TSource, TValue>> source,
    TValue value1, TValue value2)
{
    var value1Expr = Expression.Constant(value1);
    var value2Expr = Expression.Constant(value2);
    var newExpr = comparison.CompareExpr(source.Body, value1Expr, value2Expr);
    return Expression.Lambda<Func<TSource, bool>>(newExpr, source.Parameters);
}
public static Expression CompareExpr(
    this Enums.ComparisonOperator comparison,
    Expression exprLeft,
    Expression exprRight1, Expression exprRight2)
{
    switch (comparison)
    {
        case Enums.ComparisonOperator.IsLessThan:
            return Expression.LessThan(exprLeft, exprRight1);
        case Enums.ComparisonOperator.IsLessThanOrEqualTo:
            return Expression.LessThanOrEqual(exprLeft, exprRight1);
        case Enums.ComparisonOperator.IsGreaterThan:
            return Expression.GreaterThan(exprLeft, exprRight1);
        case Enums.ComparisonOperator.IsGreaterThanOrEqualTo:
            return Expression.GreaterThanOrEqual(exprLeft, exprRight1);
        case Enums.ComparisonOperator.IsBetween:
            return Expression.AndAlso(
                Expression.GreaterThanOrEqual(exprLeft, exprRight1),
                Expression.LessThanOrEqual(exprLeft, exprRight2));
        default:
            return Expression.Equal(exprLeft, exprRight1);
    }
}

Изменить: я изменил методы выше, чтобы они были универсальными.

person Daniel Baker    schedule 08.05.2012