Преобразование метода расширения в выражения LINQ и общие методы - PullRequest
3 голосов
/ 17 ноября 2011

У меня есть метод Extension, который делает следующее:

public static bool Between(this DateTime target, DateTime startDate, DateTime endDate)
{
    return target >= startDate && target <= endDate;
}

, и я могу назвать его так

if (expectedDate.Between(minDate, maxDate)) { do code }

Я сейчас пытаюсь использовать это в Linq /Лямбда-выражение типа

    return list.Where(item => targetDate.Between(item.StartDate, item.EndDate));
OR  if (!list.Any(pp => targetDate.Between(pp.StartDate, pp.EndDate)))

и я получаю следующую ошибку во время выполнения:

LINQ to Entities не распознает метод Boolean Between (System.DateTime, System.DateTime,System.DateTime) ', и этот метод нельзя преобразовать в выражение хранилища.

Но это нормально

if (!list.Any(item => targetDate >= item.StartDate && quoteDate.EventDate <=item.EndDate)))

Я хотел бы иметь общий метод для вызова,Какие у меня варианты?

Ответы [ 3 ]

4 голосов
/ 18 ноября 2011

Простая модификация решения Брайана, не требующая AsExpandable():

public static IQueryable<TSource> Between<TSource, TKey>(
    this IQueryable<TSource> source, TKey key,
    Expression<Func<TSource, TKey>> lowSelector,
    Expression<Func<TSource, TKey>> highSelector)
    where TKey : IComparable<TKey>
{
    Expression low = lowSelector.Body;
    Expression high = highSelector.Body;

    Expression lowerBound = Expression.LessThanOrEqual(
        low, Expression.Constant(key));
    Expression upperBound = Expression.LessThanOrEqual(
        Expression.Constant(key), high);

    var lowLambda = Expression.Lambda<Func<TSource, bool>>(
        lowerBound, lowSelector.Parameters);
    var highLambda = Expression.Lambda<Func<TSource, bool>>(
        upperBound, highSelector.Parameters);

    return source.Where(lowLambda).Where(highLambda);
}
3 голосов
/ 17 ноября 2011

Поскольку вы не используете LINQ to Object, запрос не выполняется, а транслируется в дерево выражений для преобразования в SQL.
LINQ to Entities не знает, как перевести метод, который вы написали, в SQL, так как вы его реализовали.
Я никогда не использовал LINQ to Entities, но должен быть способ расширить конструктор дерева выражений, чтобы позволить LINQ to Entities преобразовать ваш метод в SQL, LINQ to NHibernate может это сделать.
Здесь - пример того, как расширить поставщика LINQ to Entities.

1 голос
/ 17 ноября 2011

Я заработал, используя несколько разных методов.Построение LINQ Between Operator Я создал новый метод

public static IQueryable<TSource> Between<TSource, TKey>(this IQueryable<TSource> source, TKey key, Expression<Func<TSource, TKey>> lowSelector, Expression<Func<TSource, TKey>> highSelector)
    where TKey : IComparable<TKey>
{
    Expression low = Expression.Invoke(lowSelector, lowSelector.Parameters.ToArray());
    Expression high = Expression.Invoke(highSelector, highSelector.Parameters.ToArray());

    Expression lowerBound = Expression.LessThanOrEqual(low, Expression.Constant(key));
    Expression upperBound = Expression.LessThanOrEqual(Expression.Constant(key),  high);

    Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(lowerBound, lowSelector.Parameters);
    Expression<Func<TSource, bool>> lambda2 = Expression.Lambda<Func<TSource, bool>>(upperBound, highSelector.Parameters);
    return source.AsExpandable().Where(lambda).Where(lambda2);
}

Это не сработало, если я не использовал AsExpandable или ToList ().

AsExpandable () isиз LinkKit

ToList () переводит его из Linq в сущности в Linq To Objects, но выполняет SQL.

Спасибо за вашу помощь и предложения

...