2011-03-23 15 views
10

Esto ha estado arruinando mi vida por unos días ahora, tiempo para preguntar ...IN y NOT IN con LINQ a Entidades (EF4.0)

Estoy utilizando Entity Framework 4.0 para mi aplicación.

una ubicación (como una casa u oficina) tiene una o más instalaciones (como un cuarto de baño, dormitorio, mesa de billar, etc ..)

quiero mostrar una lista casilla de verificación en la página de localización, con una casilla de verificación de instalaciones, con las que se verificó que la ubicación tiene actualmente.

Mi Ver Modelo de las instalaciones es la siguiente ...

public class FacilityViewItem 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public bool Checked { get; set; } 
} 

Así que cuando estoy pasando la localización Vista Modelo de la interfaz de usuario, quiero pasar un List<T> de las instalaciones donde T es de tipo FacilityViewItem.

Para obtener las facilidades que la ubicación ya tiene es simple - realizo una consulta usando Location.Facilities que devuelve una EntityCollection donde T es de tipo Facility. Esto se debe a las instalaciones es una propiedad de navegación ....

var facs = from f in location.Facilities 
select new FacilityViewItem() 
{ 
    Id = f.FacilityId, 
    Name = f.Name, 
    Checked = true 
}; 

Así que aquí es donde radica mi problema - quiero que el resto de las instalaciones, las que la ubicación no tiene.

He intentado usar Except() y Any() y Contiene() pero me sale el mismo error.

ejemplos de consultas que no funcionan ...

var restOfFacilities = from f in ctx.Facilities 
    where !hasFacilities.Contains(f) 
    select new FacilityViewItem() 
     { 
      Id = f.FacilityId, 
      Name = f.Name 
     }; 

var restOfFacilities = ctx.Facilities.Except(facilitiesThatLocationHas); 

var notFacs = from e in ctx.Facilities 
where !hasFacilities.Any(m => m.FacilityId == e.FacilityId) 
    select new FacilityViewItem() 
     { 
      Id = e.FacilityId, 
      Name = e.Name 
     }; 

Y el error que consigo con cada aplicación ...

System.NotSupportedException fue controlada Mensaje = No se puede crear un valor constante del tipo 'Chapter2ConsoleApp.Facility'. En este contexto solo se admiten tipos primitivos ('como Int32, String y Guid').

¿Qué estoy pasando por alto aquí?

Respuesta

19

irónicamente Lo resuelto en cuestión de horas después de que envió la pregunta aquí, después de días de sufrimiento.

El error es básicamente decir 'no sé cómo calcular qué elementos no se incluyen al comparar objetos muy tipados. Dame una lista de Ints o algunos tipos simples, y puedo ocuparme de eso '.

Así, en primer lugar usted necesita para obtener una lista de las claves primarias, a continuación, el uso que en la cláusula contiene ...

//get the primary key ids... 
var hasFacilityIds = from f in hasFacilities 
    select f.FacilityId; 

//now use them in the contains clause... 
var restOfFacilities = from f in ctx.Facilities 
    where !hasFacilityIds.Contains(f.FacilityId) 
     select new FacilityViewItem() 
      { 
       Id = f.FacilityId, 
       Name = f.Name 
      }; 
7

La primera consulta se parece muy bien, pero hay que comparar los Id s:

var restOfFacilities = from f in ctx.Facilities 
         where !facs.Select(fac => fac.Id).Contains(f.Id) 
         select f; 
+0

Eso da exactamente el mismo error que los 3 consultas Ya he probado. – Baldy

+0

... ¡aunque hubo un error en mi cita original de esa consulta! – Baldy

1

Quiero ver lo que hay hasFacilities, de todos modos, como muestra L2e, "Sólo primitiva tipos ('como Int32, String y Guid') son compatibles en este contexto ", por lo que supongo que debe recuperar primero los datos y ponerlos en una colección de FacilityViewItem.

var restOfFacilities = ctx 
    .Facilities 
    .Where(f => !hasFacilities.Contains(f)) 
    .Select(f => new { f.FacilityId, f.Name }) 
    .ToList() 
    .Select(f => new FacilityViewItem { 
     Id = f.FacilityId, 
     Name = f.Name 
    }); 

var notFacs = ctx 
    .Facilities 
    .Where(e => !hasFacilities.Any(m => m.FacilityId == e.FacilityId)) 
    .Select(e => new { e.FacilityId, e.Name }) 
    .ToList() 
    .Select(e => new FacilityViewItem { 
     Id = e.FacilityId, 
     Name = e.Name 
    }); 

creo que sirve