2012-05-23 12 views
5

En linq to Entities necesitábamos un método que funcionara como "sql like". Hemos implementado nuestro propio método de extensión a IQueryable, porque contiene método no funciona para nosotros porque no acepta patrones como '% a% b%'Método de extensión en where cláusula en linq a Entidades

El código creado es:

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); 
} 

Esto funciona correctamente y el código se ejecuta en su totalidad en SqlServer, pero ahora sería utilizar este método de extensión en el interior donde cláusula como:

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

el problema es que los métodos utilizados en la cláusula where tiene que devolver un resultado booleano, si es lo que solía con operadores como '||' , y no sé cómo hacer que el código que he creado devuelva un bool y mantenga el código ejecutado en sqlserver. Supongo que tengo que convertir el método Expression by BuildLinqExpression devuelto a bool, pero no sé cómo hacerlo

En resumen! En primer lugar, es posible crear nuestros propios métodos de extensión en Linq para las entidades que ejecutan el código en SqlServer. si esto es posible, ¿cómo debo hacerlo?

Gracias por su ayuda.

+2

¿Usted intentó utilizar [ 'SqlMethods.Like'] (http: // MSDN. microsoft.com/en-us/library/system.data.linq.sqlclient.sqlmethods.like.aspx)? – dasblinkenlight

+0

@dasblinkenlight SqlMethods no se puede usar en Linq to Entity. –

Respuesta

3

No, no puede educar a EF para que procese sus métodos de extensión personalizados, aunque tenga código que genere expresiones que serían utilizables para EF.

O bien:

  • utilizan los métodos SqlFunctions directamente en su EF Where expresión
  • utilizar un ExpressionVisitor para combinar múltiples expresiones en un compuesto (OrElse/AndAlso) expresión (tenga en cuenta que esto no le ayudará a tener código como desee, pero le permitirá usar sus dos métodos y realizar un || en ellos - se verá complejo, sin embargo)

El primero es más simple y claro.

+0

Si no estoy equivocado, SqlMethods no se puede usar en linq para Entidades, lo he probado y me cuelga. Otros usuarios informaron de la misma http://stackoverflow.com/questions/2584598/linq-sqlmethods-like-fails –

+0

@Marc lo siento, probablemente quise decir 'SqlFunctions' - es decir, el código que ya está utilizando bajo el capó –

+0

@Marc y : si esa es tu propia clase, entonces: no hay nada que puedas hacer. Tal vez simplemente escriba SQL y empuje hacia abajo * a través de * EF en lugar de intentar escribir LINQ. –

2

respondida aquí: https://stackoverflow.com/a/10726256/84206

Su código: http://pastebin.com/4fMjaCMV

le permite etiquetar un método de extensión como [Expandable] y siempre y cuando la expresión se vuelve trabajos con linq2entities, que sustituirá a la llamada a la función con el interior expresión. Tenga en cuenta que en línea lambdas dan errores, así que tuve que declarar como variables locales o variable estática como la variable IsCurrent aquí:

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); 
} 
Cuestiones relacionadas