扩展方法转换为LINQ表达式和常用方法

时间:2011-11-16 22:38:12

标签: linq datetime c#-4.0 linq-to-entities linq-expressions

我有一个执行以下操作的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 / Lambda表达式中使用它,如

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

我在运行时遇到以下错误:

  

LINQ to Entities无法识别方法'布尔值   之间(System.DateTime,System.DateTime,System.DateTime)'方法,   并且此方法无法转换为商店表达式。

但这很好

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

我想要一个通用的方法来调用。我有什么选择?

3 个答案:

答案 0 :(得分:4)

简单修改Brian的解决方案,不需要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);
}

答案 1 :(得分:3)

由于您没有使用LINQ to Object,因此查询未被执行,而是转换为expression tree以转换为SQL。
LINQ to Entities在您实现它之后不知道如何将您编写的方法转换为SQL 我从未使用LINQ to Entities,但必须有一种方法来扩展表达式树构建器以使LINQ to Entities能够将您的方法转换为SQL,LINQ to NHibernate有办法这样做。
Here是如何将LINQ扩展为实体提供程序的示例。

答案 2 :(得分:1)

我使用了几种不同的方法。建立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()来自LinkKit

ToList()强制它从Linq到实体进入Linq To Objects,但执行SQL。

感谢您的帮助和建议