2012-09-05 28 views
5

Esto me ha causado infinitos problemas hoy. Tengo esta consulta sencillaEntity Framework: no se puede crear un valor constante de tipo 'System.Collections.Generic.IList`1'

var result = 
    DataContext.Accommodations.Where(a => 
     (criteria.MinPrice == null || a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) && 
     (criteria.MaxPrice == null || a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice)) && 
     (criteria.Locations == null || criteria.Locations.Count == 0 || a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName))) 
); 

La última línea de esta consulta me está causando problemas

(criteria.Locations == null || 
criteria.Locations.Count == 0 || 
a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName))) 

El error que da es

No se puede crear un valor constante de tipo ' System.Collections.Generic.IList`1 '. En este contexto, solo se admiten tipos primitivos ('como Int32, String y Guid').

Ni siquiera estoy tratando de crear una lista. Todo lo que trato de hacer aquí es traer de vuelta los alojamientos que están asociados a un lugar (donde el nombre del lugar en la tabla de Place que está vinculado a la tabla de Alojamiento a través de la tabla AccommodationPlaceJoin) es igual a cualquiera de los nombres de los lugares en los criterios .Locations (que es del tipo IList).

He intentado cambiar esta línea a esto, pero no funcionó.

(criteria.Locations == null || 
criteria.Locations.Count == 0 || 
a.AccommodationPlaceJoins.Any(j => criteria.Locations.Any(l => l == j.Place.PlaceName))) 

Respuesta

29

El EF valor constante no puede crear es null para la comparación criteria.Locations == null. Es necesario dividir la consulta en dos casos y hacer la comprobación de la lista vacía fuera de la consulta, por ejemplo, así:

var result = DataContext.Accommodations.Where(a => 
    (criteria.MinPrice == null || 
     a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) && 
    (criteria.MaxPrice == null || 
     a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice))); 

if (criteria.Locations != null && criteria.Locations.Count > 0) 
{ 
    result = result.Where(a => a.AccommodationPlaceJoins 
     .Any(j => criteria.Locations.Contains(j.Place.PlaceName))); 
} 

Editar

Por cierto: Composición de toda la consulta haría mejor legible en mi opinión y simplificará el SQL que debe enviarse a la base de datos:

IQueryable<Accommodation> result = DataContext.Accommodations; 

if (criteria.MinPrice != null) 
    result = result.Where(a => a.AccommodationRates 
     .Any(r => r.From >= criteria.MinPrice)); 

if (criteria.MaxPrice != null) 
    result = result.Where(a => a.AccommodationRates 
     .Any(r => r.To <= criteria.MaxPrice)); 

if (criteria.Locations != null && criteria.Locations.Count > 0) 
    result = result.Where(a => a.AccommodationPlaceJoins 
     .Any(j => criteria.Locations.Contains(j.Place.PlaceName))); 
+0

Vaya, qué gran respuesta. Un millón de gracias. Bajé tantas líneas de investigación erróneas. Gracias +1 y respuesta aceptada y pregunta favorita. No es de extrañar que tenga casi 29K puntos. ¿Por qué sucede esto de todos modos? –

+0

Estoy refactorizando de acuerdo con su sugerencia de legibilidad. Gracias. –

+1

@SachinKainth: La excepción se produce porque en LINQ to Entities cada fragmento de expresión y expresión en una consulta debe ser traducible a SQL. La comparación 'criteria.Locations == null' no se realiza en el lado del cliente (= .NET), sino que EF también quiere traducirlo a SQL y luego se supone que la base de datos debe realizar la comparación. Pero la base de datos no sabe cómo comparar referencias de objetos .NET/CLR, solo puede verificar tipos primitivos como string, int, etc. para 'NULL'. Ninguna traducción a SQL posible o compatible -> Excepción. – Slauma

Cuestiones relacionadas