6

在 linq to Entities 中,我们需要一种类似于“sql like”的方法。我们已经为 IQueryable 实现了自己的扩展方法,因为 contains 方法对我们不起作用,因为它不接受像 '%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 子句中使用的方法必须返回一个布尔结果,如果它与像 '||' 这样的运算符一起使用的话 ,而且我不知道如何使我创建的代码返回一个布尔值并保持代码在 sqlserver 中执行。我想我必须将 BuildLinqExpression 方法返回的表达式转换为布尔值,但我不知道该怎么做

总结一下!首先,是否可以在 Linq 中创建我们自己的扩展方法来执行 SqlServer 中的代码的实体?如果这是可能的,我该怎么做?

谢谢你的帮助。

4

2 回答 2

3

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

任何一个:

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

第一个更简单,更清晰。

于 2012-05-23T10:52:02.940 回答
2

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

His code: http://pastebin.com/4fMjaCMV

Allows you to tag an extension method as [Expandable] and so long as the expression it returns works with linq2entities, it will replace your function call with the inner expression. Note that inline lambdas give errors, so I had to declare them as local variables or static variable such as the IsCurrent variable here:

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);
}
于 2012-06-05T17:28:53.327 回答