NH QueryOver: как объединить выражение члена в другое выражение? - PullRequest
3 голосов
/ 15 апреля 2011

Я пытаюсь сделать метод расширения для ограничений на DateTime? имущество. Это для поискового запроса, и я действительно не хочу дублировать этот код для всех возможных полей даты.

public static IQueryOver<T, T> WhereInOpenEndedDateRange<T>(this IQueryOver<T, T> query, 
    Expression<Func<object>> field, 
    DateTime? rangeFrom, 
    DateTime? rangeTo)
{
    if(rangeFrom.HasValue && rangeTo.HasValue)
    {
        query.WhereRestrictionOn(field).IsBetween(rangeFrom.Value).And(rangeTo.Value);
    }
    else if (rangeFrom.HasValue)
    {
        //query.Where(() => /* help */ >= rangeFrom.Value);
    }
    else if (rangeTo.HasValue)
    {
        //query.Where(() => /* help */ <= rangeTo.Value);
    }

    return query;
}

Я думаю, что мне не хватает фундаментального аспекта выражений. Можно ли передать какой-либо параметр Expression и использовать его в /* help */ точках?

Спасибо

обновление

все ближе, но все еще чувствую себя очень далеко ...

else if (rangeFrom.HasValue)
{
    var lt = Expression.LessThanOrEqual(field, Expression.Constant(rangeFrom, typeof(DateTime?)));
    var b = Expression.Lambda<Func<bool>>(lt);
    query.Where(b);
}

но это не сработает, так как это будет сравнение Func<object> с DateTime?. Как я могу объединить исходное выражение свойства в новый Func<bool> и сохранить необходимые биты, чтобы сохранить тактичность NH QueryOver?

После просмотра источника NH для QueryOverRestrictionBuilder я сделаю

string propertyName = ExpressionProcessor.FindMemberExpression(field.Body)

и создайте методы Ограничения с помощью критериев.

1 Ответ

2 голосов
/ 24 мая 2011

Ну, я не мог понять, как это сделать, используя

Expression<Func<bool>> 

подпись, но в любом случае это только для DateTime? S, поэтому я не вижу, как добавит ограничение, которое я добавиллюбая разница.

По сути, вам нужно выражение (поле в вашем примере), чтобы точно соответствовать параметру, который вы отправляете, то есть x => x.SomeNullableDateField.'x' - это тип запроса, который вы начали с

session.QueryOver<YourClass>()

, поэтому его необходимо было включить в тип отправляемого выражения. Вы также пропустили получение этого параметра, используя

ParameterExpression param = expression.Parameters.Single() 

, который будет использоваться для построения выражений сравнения.

Вы должны были преобразовать BinaryExpression в Expression<Func<bool>>, но вам пришлось сделать еще один шаг вперед к Expression<Func<T, bool>>.

public static IQueryOver<T, T> WhereInOpenEndedDateRange<T>(this IQueryOver<T, T> query,
    Expression<Func<T, DateTime?>> expression,
    DateTime? rangeFrom,
    DateTime? rangeTo) where T : class
{
    // Lambda being sent in
    ParameterExpression param = expression.Parameters.Single();

    if(rangeFrom.HasValue && rangeTo.HasValue)
    {
        // GT Comparison
        var expressionGT =
            Expression.GreaterThanOrEqual(
                expression.Body,
                Expression.Constant(rangeFrom.Value, typeof(DateTime?)
            )
        );

        // LT Comparison
        var expressionLT =
            Expression.LessThanOrEqual(
                expression.Body,
                Expression.Constant(rangeTo.Value, typeof(DateTime?)
            )
        );

        query.Where(
               Expression.Lambda<Func<T, bool>>(expressionGT, param))
               .And(
               Expression.Lambda<Func<T, bool>>(expressionLT, param)
        );
    }
    else if(rangeFrom.HasValue)
    {
        // GT Comparison
        BinaryExpression expressionGT =
            Expression.GreaterThanOrEqual(
                expression.Body,
                Expression.Constant(rangeFrom.Value, typeof(DateTime?)
            )
        );

        // covert to lambda
        query.Where(Expression.Lambda<Func<T, bool>>(expressionGT, param));
    }
    else if(rangeTo.HasValue)
    {
        // LT Comparison
        BinaryExpression expressionLT =
            Expression.LessThanOrEqual(
                expression.Body,
                Expression.Constant(rangeTo.Value, typeof(DateTime?)
            )
        );

        query.Where(Expression.Lambda<Func<T, bool>>(expressionLT, param));
    }

    return query;

}

Использование

var test = session.QueryOver<MyPocoClass>()
            .WhereInOpenEndedDateRange(x=>x.SomeNullableDateField, DateTime.Now, null);
...