Entity Framework: error "No se puede crear un valor constante de tipo 'Tipo de cierre' ..."


79

¿Por qué recibo el error?

No se puede crear un valor constante de tipo 'Tipo de cierre'. En este contexto, solo se admiten los tipos primitivos (por ejemplo, Int32, String y Guid).

¿Cuando intento enumerar la siguiente consulta de Linq?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

Actualización : si intento lo siguiente solo para tratar de aislar el problema, aparece el mismo error:

where upperSearchList.All(arg => arg == arg) 

Entonces, parece que el problema está en el método All, ¿verdad? ¿Alguna sugerencia?

Respuestas:


68

Parece que estás intentando hacer el equivalente a una condición "DÓNDE ... EN". Consulte Cómo escribir consultas de estilo 'DÓNDE EN' usando LINQ to Entities para ver un ejemplo de cómo hacer ese tipo de consulta con LINQ to Entities.

Además, creo que el mensaje de error es particularmente inútil en este caso porque .Containsno va seguido de paréntesis, lo que hace que el compilador reconozca todo el predicado como una expresión lambda.


Gracias Daniel. La misma sintaxis funciona bien con Linq simple. Entonces, parece que el problema es con EF en .Net 3.5 SP1, ¿verdad? Contiene sin paréntesis es equivalente a: donde UpperSearchList.All (x => (person.FirstName + person.LastName) .Contains (x)). ToList ();
Gus Cavalcanti

Si intento donde upperSearchList.All (arg => arg == arg) arroja el mismo error. Entonces el problema es con el método All ...
Gus Cavalcanti

2
LINQ to Entities es una tecnología maravillosa, pero el motor de traducción SQL es limitado. No puedo poner mis manos en la documentación oficial, pero en mi experiencia, si la consulta incluye más que solo funciones matemáticas básicas y de cadena / fecha, no va a funcionar. ¿Has tenido la oportunidad de ver esa publicación que vinculé? Describe un proceso de conversión de una consulta de tipo "WHERE..IN" en un formulario que LINQ to Entities puede luego traducir a SQL.
Daniel Pratt

No puede usar punteros de función en linq a entidades. El proveedor no sabe cómo extraerlo de un árbol de expresión para convertirlo a SQL.
Sinaesthetic

@DanielPratt su enlace está roto
Mick

11

He pasado los últimos 6 meses luchando contra esta limitación con EF 3.5 y, aunque no soy la persona más inteligente del mundo, estoy bastante seguro de que tengo algo útil que ofrecer sobre este tema.

El SQL generado por el crecimiento de un árbol de 50 millas de alto de expresiones de "estilo OR" dará como resultado un plan de ejecución de consulta deficiente. Estoy tratando con unos pocos millones de filas y el impacto es sustancial.

Hay un pequeño truco que encontré para hacer un SQL 'en' que ayuda si solo está buscando un montón de entidades por id:

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

donde pkIDColumn es el nombre de la columna de identificación de la clave principal de su tabla Entity1.

¡PERO SIGUE LEYENDO!

Esto está bien, pero requiere que ya tenga los identificadores de lo que necesito encontrar. A veces solo quiero que mis expresiones lleguen a otras relaciones y lo que sí tengo son criterios para esas relaciones conectadas.

Si tuviera más tiempo, trataría de representar esto visualmente, pero no me limito a estudiar esta oración un momento: considere un esquema con tablas Person, GovernmentId y GovernmentIdType. Andrew Tappert (Person) tiene dos tarjetas de identificación (GovernmentId), una de Oregon (GovernmentIdType) y otra de Washington (GovernmentIdType).

Ahora genere un edmx a partir de él.

Ahora imagine que desea encontrar a todas las personas que tengan un determinado valor de ID, digamos 1234567.

Esto se puede lograr con un solo acceso a la base de datos con esto:

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

¿Ves la subconsulta aquí? El sql generado usará 'uniones' en lugar de subconsultas, pero el efecto es el mismo. En estos días, el servidor SQL optimiza las subconsultas en combinaciones bajo las cubiertas de todos modos, pero de todos modos ...

La clave para este trabajo es el .Any dentro de la expresión.


8

Encontré la causa del error (estoy usando Framework 4.5). El problema es que EF, un tipo complejo, que se pasa en el parámetro "Contiene", no se puede traducir a una consulta SQL. EF puede usar en una consulta SQL solo tipos simples como int, string ...

this.GetAll().Where(p => !assignedFunctions.Contains(p))

GetAll proporciona una lista de objetos con un tipo complejo (por ejemplo: "Función"). Por lo tanto, aquí intentaría recibir una instancia de este tipo complejo en mi consulta SQL, ¡que naturalmente no puede funcionar!

Si puedo extraer de mi lista los parámetros que se adapten a mi búsqueda, puedo usar:

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

Ahora EF ya no tiene el tipo complejo "Función" para trabajar, sino, por ejemplo, con un tipo simple (largo). ¡Y eso funciona bien!


0

Recibí este mensaje de error cuando mi objeto de matriz utilizado en la función .All es nulo Después de inicializar el objeto de matriz (upperSearchList en su caso), el error desapareció El mensaje de error fue engañoso en este caso

donde upperSearchList.All (arg => persona.algunospropiedades.StartsWith (arg)))

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.