linq a las entidades no reconoce un método

Tengo esos métodos:

public int count( Guid companyId, Expression<Func> isMatch) { var filters = new Expression<Func>[]{ x => x.PriceDefinition.CompanyId == companyId, isMatch }; return GetCount(filters); } public virtual int GetCount( IEnumerable<Expression<Func>> filters) { IQueryable _query = ObjectSet; if (filters != null) { foreach (var filter in filters) { _query = _query.Where(filter); } } return _query.Count(); } 

Cuando usas:

 count(some_guid, x => x.IsMatch(entityId, inviterId, routeId, luggageTypeId)); 

Obtengo la siguiente excepción:

 LINQ to Entities does not recognize the method 'Boolean IsMatch(System.Nullable`1[System.Int64], System.Nullable`1[System.Int64], System.Nullable`1[System.Int64], System.Nullable`1[System.Int64])' method, and this method cannot be translated into a store expression. 

¿Cuál es la razón para esto?
¿Cómo puedo resolverlo?

Al usar linq-to-entities no puede usar métodos arbitrarios de .NET en la consulta. Cada método utilizado en la consulta debe ser traducible a SQL. No le ayudará a devolver Expession> porque se debe evaluar la condición para cada registro en el servidor de la base de datos.

Para EF tu código significa algo así como:

 SELECT COUNT(*) FROM ... LEFT JOIN ... WHERE IsMatch(....) 

Como EF valida los nombres de funciones pasados ​​a la consulta arrojará una excepción porque no conoce el equivalente de IsMatch en el servidor SQL.

Las únicas funciones posibles que se pueden usar en Linq-to-entities son:

  • Funciones canónicas con asignación predefinida a SQL equivalente
  • EdmFunctions

Las funciones Edm son métodos marcados con EdmFunctionAttribute que mapea la función .NET con la contraparte SQL. Esas funciones generalmente no se pueden ejecutar en el código .NET común porque no hacen nada o lanzan una excepción. Son solo el titular del lugar de función para Linq-a-entidades. Las funciones Edm disponibles son:

  • Funciones Edm predefinidas en System.Data.Objects.EntityFunctions
  • EdmFunctions predefinidas para SQL Server (no compactas) en System.Data.Objects.SqlClient.SqlFunctions
  • Funciones SQL asignadas personalizadas: el asistente de importación en el diseñador de Entidades le permite importar funciones de SQL (excepto funciones con valores de tabla). Después de eso, puede escribir la función .NET estática personalizada y EdmFunction por el atributo EdmFunction a la función SQL importada al diseñador.
  • Funciones definidas por el modelo personalizado: esta es una función especial escrita manualmente en un archivo EDMX (abierto como XML). Es una parte reutilizable personalizada de Entity SQL.

Ya he descrito cómo crear una función definida por modelo en otra respuesta. La creación de la función SQL asignada es bastante similar . En lugar de crear manualmente el elemento Function en EDMX, EdmFunctionAttribute propiedades EdmFunctionAttribute a la función SQL importada.

Está pasando una expresión que llama a una función llamada IsMatch .

LINQ to Entities no sabe qué hacer con esta función.

Estaba lidiando con un problema similar. La solución de trabajo estaba usando .AsEnumerable() antes de intentar usar mi método personalizado. Puedes echarle un vistazo aquí .

En realidad, lo que está pasando para contar se parece a esta función:

 bool anonymous_delagate#123(T entity) { return entity.IsMatch(a,b,c,d) } 

Pero, esto requeriría que EF supiera qué significa realmente el método IsMatch , llamado en esta entidad.

Lo único que puedo pensar en recomendar ahora es usar algún tipo de forjado dynamic de expresiones para crear esta consulta dinámicamente. O reelabora tu diseño para algo diferente.

En realidad, hay un método más fácil y normal que requiere pocos pasos para lograrlo.

  1. Hacer el método IsMatch estático.
  2. Devuelve Expression<{your entity here}, bool> directamente desde IsMatch .
  3. Pásalo como: ({your entity here}.IsMatch({parameters}))

El descanso puede permanecer igual que ahora.

Editar: Ejemplo Esto funcionará con una entidad específica, por lo que su entidad será Orden . Sustituye tu propia entidad.

 public static Expression> IsMatch(int id, ...) // static method, that returns filtering expression { return i => i.Id == id; // create the filtering criteria } 

Entonces llámalo así:

 count(some_guid, Order.IsMatch(entityId, inviterId, routeId, luggageTypeId));