2011-02-01 17 views
8

He definido una clase GenericRepository que realiza la interacción db.Soluciones para el uso de métodos personalizados/métodos de extensión en LINQ to Entidades

protected GenericRepository rep = new GenericRepository(); 

Y en mis clases BLL, que puede consultar la base de datos como:

public List<Album> GetVisibleAlbums(int accessLevel) 
{ 
    return rep.Find<Album>(a => a.AccessLevel.BinaryAnd(accessLevel)).ToList(); 
} 

BinaryAnd es un método de extensión que comprueba dos valores int poco a poco. p.ej. AccessLevel=5 =>AccessLevel.BinaryAnd(5) y AccessLevel.binaryAnd(1) ambos devuelven verdadero.

Sin embargo, no puedo usar este método de extensión en mis consultas LINQ. Obtengo un error de tiempo de ejecución de la siguiente manera:
LINQ to Entities does not recognize the method 'Boolean BinaryAnd(System.Object, System.Object)' method, and this method cannot be translated into a store expression.

También traté de cambiarlo a un método personalizado, pero no tuve suerte. ¿Cuáles son las soluciones?

¿Debo obtener todos los álbumes y luego iterarlos a través de un bucle foreach y elegir los que coincidan con los AccessLevels?

Respuesta

7

Solo puede usar core extension methods and CLR methods defined for your EF provider cuando usa Entity Framework y consultas en IQueryable<T>. Esto se debe a que la consulta se traduce directamente al código SQL y se ejecuta en el servidor.

Puede transmitir la colección completa (usando .ToEnumerable()) luego consultar esto localmente, o convertir esto a un método que su proveedor puede traducir directamente a SQL.

Dicho esto, basic bitwise operations are supported:

El bitwise AND, OR, NOT, y los operadores XOR también se asignan a funciones canónicas cuando el operando es un tipo numérico.

Por lo tanto, si reescribe esto para no utilizar un método, y solo realiza la operación bit a bit en el valor directamente, debería funcionar según sea necesario. Pruebe algo como lo siguiente:

public List<Album> GetVisibleAlbums(int accessLevel) 
{ 
    return rep.Find<Album>(a => (a.AccessLevel & accessLevel > 0)).ToList(); 
} 

(No estoy seguro exactamente cómo funciona su método de extensión actual - lo anterior sería comprobar para ver si alguna de las banderas vuelven cierto, que parece coincidir con su estado de cuenta .. .)

+0

Gracias Reed. Supongo que es la única forma. – Kamyar

+0

@Kamyar: Simplemente debería ser una cuestión de no usar el método de extensión, y poner el código real en la consulta - ver mi edición. –

8

Me doy cuenta de que esto ya tiene una respuesta aceptada, solo pensé en publicar esto en caso de que alguien quisiera intentar escribir un interceptor de expresión LINQ.

Así que ... aquí es lo que hice para hacer que los métodos de extensión personalizada traducibles: Code Sample

las que no creo que esto sea una solución final, pero es de esperar que debería proporcionar un buen punto de partida para cualquier persona lo suficientemente valiente para verlo hasta su finalización

+0

Encontré que en el método de extensión '.Where (p => p.Key == 25)' da un error sobre p ser desatado. Así que tuve que declarar el lambda así 'Expression > exp = (p) => p.Key == 25;' y luego usarlo en '.Where (exp)'. Teniendo en cuenta la reutilización de la extensión, sigue siendo excelente. Hay una recompensa abierta aquí si quieres publicar tu respuesta. Realmente agradecería que publicaras un comentario si actualizas tu código. Esto es digno de un proyecto Codeplex, creo. http://stackoverflow.com/questions/10826275/extension-extension-method-for-linq2entities – AaronLS

+1

@AaronLS De hecho, lo actualicé. Quería agregar soporte para consultas compiladas y método de extensión personalizado para traducciones de expresiones. Todavía no estoy seguro de si es una buena solución, solo estaba probando cosas. Puedes verlo aquí: [Código] (http://pastebin.com/G3QXS1gb) –

+0

Esto es súper increíble, debes ponerlo en nuget –

Cuestiones relacionadas