linq to Entities中where子句中的扩展方法

时间:2012-05-23 10:44:52

标签: c# entity-framework linq-to-entities

在linq to Entities中,我们需要一个像“sql like”一样工作的方法。我们已经为IQueryable实现了我们自己的扩展方法,因为包含的方法对我们不起作用,因为它不接受像'%a%b%'这样的模式

创建的代码是:

private const char WildcardCharacter = '%';

public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> _source, Expression<Func<TSource, string>> _valueSelector, string _textSearch)
{
    if (_valueSelector == null)
    {
        throw new ArgumentNullException("valueSelector");
    }

        return _source.Where(BuildLikeExpressionWithWildcards(_valueSelector, _textSearch));
}

private static Expression<Func<TSource, bool>> BuildLikeExpressionWithWildcards<TSource>(Expression<Func<TSource, string>> _valueSelector, string _textToSearch)
{
    var method = GetPatIndexMethod();

    var body = Expression.Call(method, Expression.Constant(WildcardCharacter + _textToSearch + WildcardCharacter), _valueSelector.Body);

    var parameter = _valueSelector.Parameters.Single();
    UnaryExpression expressionConvert = Expression.Convert(Expression.Constant(0), typeof(int?));
    return Expression.Lambda<Func<TSource, bool>> (Expression.GreaterThan(body, expressionConvert), parameter);
}

private static MethodInfo GetPatIndexMethod()
{
    var methodName = "PatIndex";

    Type stringType = typeof(SqlFunctions);
    return stringType.GetMethod(methodName);
}

这是正常的,代码完全在SqlServer中执行,但现在我们将在where子句中使用此扩展方法:

myDBContext.MyObject.Where(o => o.Description.Like(patternToSearch) || o.Title.Like(patterToSerch));

问题是where子句中使用的方法必须返回bool结果,如果它与'||'之类的运算符一起使用,我不知道如何使我创建的代码返回一个bool并保持代码在sqlserver中执行。我想我必须通过BuildLinqExpression方法将返回的Expression转换为bool,但我不知道该怎么做

总结一下!首先,可以在Linq to Entities中创建我们自己的扩展方法,以便在SqlServer中执行代码吗?如果这是可能的我怎么做呢?

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

不,您无法教育EF处理您的自定义扩展方法,即使您拥有构建 可用于EF的表达式的代码。

或者:

  • 直接在您的EF SqlFunctions表达式
  • 中使用Where方法
  • 使用ExpressionVisitor将多个表达式组合成一个复合(OrElse / AndAlso)表达式(请注意,这不会帮助您获得所需的代码,但它会让您使用你的两种方法并对它们执行|| - 它看起来很复杂,但是)

第一个更简单,更清晰。

答案 1 :(得分:2)

在这里回答:https://stackoverflow.com/a/10726256/84206

他的代码:http://pastebin.com/4fMjaCMV

允许您将扩展方法标记为[Expandable],只要它返回的表达式与linq2entities一起使用,它将用内部表达式替换您的函数调用。请注意,内联lambda会出错,所以我必须将它们声明为局部变量或静态变量,例如IsCurrent变量:

static Expression<Func<PropertyHistory, bool>> IsCurrent = (p) => p.Starts <= DateTime.Now;

[ExpandableMethod]
public static IQueryable<PropertyHistory> AsOf(this IQueryable<PropertyHistory> source)
{
  return source.Where(IsCurrent);
}