2011-05-01 16 views
10

tengo esos métodos:LINQ a las entidades no reconoce un método

public int count(
     Guid companyId, Expression<Func<T, bool>> isMatch) 
    { 
     var filters = new Expression<Func<T, bool>>[]{ 
      x => x.PriceDefinition.CompanyId == companyId, 
      isMatch 
     }; 

     return GetCount(filters); 
    } 

public virtual int GetCount(
      IEnumerable<Expression<Func<T, bool>>> filters) 
     { 
      IQueryable<T> _query = ObjectSet; 

      if (filters != null) 
      { 
       foreach (var filter in filters) 
       { 
        _query = _query.Where(filter); 
       } 
      } 

      return _query.Count(); 
     } 

Al utilizar:

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

tengo 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 el razón por esto?
¿Cómo puedo resolverlo?

+0

¿Cuáles son sus filtros? – SLaks

+0

@ SLaks ♦: Lo siento, actualicé la pregunta con el delegado de isMatch. – Naor

Respuesta

14

Al utilizar LINQ a las entidades que no puede utilizar métodos arbitrarios en .NET consulta. Cada método utilizado en la consulta debe ser traducible a SQL. No le ayudará a devolver Expession<Func<entityType, bool>> porque se debe evaluar la condición para cada registro en el servidor de la base de datos.

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

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

Debido EF valida los nombres de funciones pasaron a la consulta se lanzará una excepción, ya que no sabe equivalente IsMatch en el servidor SQL.

Las únicas funciones posibles que pueden ser utilizados en Linq-to-entidades son:

EdmFunctions son métodos marcados con EdmFunctionAttribute que asigna la función .NET a la contraparte de 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. EdmFunctions disponibles son:

  • predefinidas EdmFunctions en System.Data.Objects.EntityFunctions
  • predefinidas EdmFunctions para SQL Server (no compacto) en System.Data.Objects.SqlClient.SqlFunctions
  • personalizada asigna funciones SQL - asistente de importación en el diseñador de entidad permite importar las funciones SQL (excepto valores de tabla funciones). Después de eso, puede escribir la función .NET estática personalizada y asignarla 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 el archivo EDMX (abierto como XML). Es una parte reutilizable personalizada de Entity SQL.

Ya he descrito how to create model defined function en otra respuesta. Creando mapeado SQL function is pretty similar. En lugar de crear manualmente el elemento Function en EDMX, asignará propiedades EdmFunctionAttribute a la función SQL importada.

2

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

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

+0

♦: Actualicé la pregunta ... – Naor

+0

LINQ to Entities no sabe cómo convertir 'IsMatch' en SQL. Necesita reemplazarlo con un árbol de expresiones. – SLaks

+3

♦: ¿Qué quiere decir con "reemplazarlo por un árbol de expresiones"? – Naor

1

Estaba lidiando con un problema similar. La solución de trabajo estaba usando .AsEnumerable() antes de intentar usar mi método personalizado. Puede take a look at it here.

+0

Agregar AsEnumerable cargará toda la tabla en la memoria y después del filtro de companyId todavía tengo muchos resultados. – Naor

+0

@Naor: Ok, funcionó para mí porque estaba trabajando con pocos resultados. No sabía sobre el tuyo – Damb

0

podía comprender, lo que está pasando a contar parece a esta función:

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

embargo, esto requeriría EF saber, lo que realmente método IsMatch, que se llama en esta entidad, significa.

Lo único que se me ocurre recomendar ahora es utilizar algún tipo de forjado dinámico de expresiones para crear esta consulta dinámicamente. O reelabora tu diseño para algo diferente.

Actualmente, hay un método más fácil y normal, que requiere pocos pasos para realizar.

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

resto puede permanecer igual que usted tiene ahora.

Editar: Ejemplo Esto funciona con entidad específica, por lo que será Asume que su entidad es Solicitar. Sustituye tu propia entidad.

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

Entonces llamar así:

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

¿Puedes proporcionar un ejemplo? No entendí tus últimos dos pasos. – Naor

+0

¿El método IsMatch estático que escribió debe devolver delegado que NO esté basado en otras funciones? ¿Puedo usar, por ejemplo, "return i => i.MyMethod (id);"? – Naor

+0

No. Debe usar eiter para crearlo completamente como expresión o, como dice Ladislav, asigne sus funciones a los procedimientos almacenados. – Euphoric

Cuestiones relacionadas