2009-07-08 10 views
17

Estoy perdido con la siguiente consulta, que es cacahuetes en T-SQL simple.Linq a entidades de muchos a muchos seleccionar consulta

Tenemos tres tablas físicas:

  • Band (PK = Bandid)
  • MusicStyle (PK = MuicStyleId)
  • BandMusicStyle (PK = Bandid + MusicStyleId, FK = Bandid, MusicStyleId)

Ahora lo que estoy tratando de hacer es obtener una lista de MusicStyles que están vinculados a una banda que contiene una determinada cadena de búsqueda en su nombre. El nombre de la banda también debe estar en el resultado.

El T-SQL sería algo como esto:

SELECT b.Name, m.ID, m.Name, m.Description 
FROM Band b 
INNER JOIN BandMusicStyle bm on b.BandId = bm.BandId 
INNER JOIN MusicStyle m on bm.MusicStyleId = m.MusicStyleId 
WHERE b.Name like '%@searchstring%' 

¿Cómo voy a escribir esto en LINQ a las entidades?

PS: StackOverflow no permite una búsqueda en la cadena 'de muchos a muchos' por alguna razón bizar ...

Respuesta

27

Esto resultó ser mucho más sencillo de lo que parecía. He resuelto el problema utilizando la siguiente entrada de blog: http://weblogs.asp.net/salimfayad/archive/2008/07/09/linq-to-entities-join-queries.aspx

La clave de esta solución es aplicar el filtro del nombre de banda en un subconjunto de Bandas de la colección de estilos de música.

var result=(from m in _entities.MusicStyle 
      from b in m.Band 
      where b.Name.Contains(search) 
      select new { 
       BandName = b.Name, 
       m.ID, 
       m.Name, 
       m.Description 
      }); 

aviso de la línea

from b IN m.Band 

Esto se asegura de que sólo se está filtrando en bandas que tienen un musicstyle.

Gracias por sus respuestas, pero ninguno de ellos realmente resolvió mi problema.

+1

si necesita una combinación de la izquierda en lugar de una combinación interna, usted puede reemplazar 'de b en m.Band' con' de b en m.Band.DefaultIfEmpty() '. –

+0

Simple, nítido y útil. Gracias hombre. – QMaster

+0

@Peter, si usamos el método linq, ¿qué método debería usar para cubrir la sintaxis 'from .... from ....'? podrías dar el ejemplo en el método linq gracias – Willy

4

en LINQ, en realidad no es necesario escribir nada, si se define la relación de el diagrama en la base de datos SQL, y generado con la utilidad, la jerarquía de objetos se crea automáticamente. Eso significa que, si lo hace:

var bands = from ms in db.MusicStyle 
      let b = ms.Bands 
      where b.Name.Contains(SEARCHSTRING) 
      select new { 
       b.Name, ms.Name, 
       ms.ID, ms.Description}; 

Si nos fijamos en las clases generadas de las entidades, la BandMusicStyle no debería aparecer como LINQ a Entidades tenemos en cuenta que la banda y MusicStyle son muchos a muchos y que la tabla no es necesario.

Ver si esto funciona?

+0

La tabla BandMusicStyle no aparece en mi modelo de datos. Solo quiero tener una lista de estilos de música que estén vinculados a una Banda con la cadena de búsqueda en su nombre. ¿Cómo obtendría una lista de objetos de su consulta con Bandname, MusicStyleId, MusicStyleName y MusicStyleDescription? No quiero tener que repetir esta lista y configurarla manualmente después ... – Peter

+0

La tabla BandMusicStyle NO aparecería en el modelo de entidad. Esto lo hace intencionadamente LINQ to Entities, porque considera que la tabla intermedia es solo una "unión many-many" para que no se genere, no como Linq 2 SQl. Si necesita SÓLO esos campos, puede seleccionarlos en su instrucción seleccionada: seleccione new {b.Name, b.MusicStyle.Name, b.MusicStyle.ID, b.MusicStyle.Description}; – xandy

+0

Sí, sé que no aparecerá ... El problema que tiene en su consulta actual es que b.Musicstyle es una colección de MusicStyles, ya que una banda puede tener múltiples MusicStyles. – Peter

0
from ms in Context.MusicStyles 
where ms.Bands.Any(b => b.Name.Contains(search)) 
select ms; 

Esto simplemente devuelve el estilo, que es lo que su pregunta pide. Su muestra de SQL, por otro lado, devuelve el estilo y las bandas. Por eso, me gustaría hacer:

from b in Context.Bands 
where b.Name.Contains(search) 
group b by band.MusicStyle into g 
select new { 
    Style = g.Key, 
    Bands = g 
} 

from b in Context.Bands 
where b.Name.Contains(search) 
select new { 
    BandName = b.Name, 
    MusicStyleId = b.MusicStyle.Id, 
    MusicStyleName = b.MusicStyle.Name, 
    // etc. 
} 
+0

¿no es posible simplemente devolver una lista de objetos nuevos que contienen los elementos que he escrito en mi declaración de SQL? – Peter

+0

Sure. No agrupe y devuelva un tipo anónimo. Añadiré un ejemplo. –

1

que podría hacer lo anterior, pero que traerá de vuelta todos sus resultados una vez que comience a iterar sobre ellos y el filtrado se realiza en memoria en lugar de en el PP.

Creo que lo que estás buscando son solo unas pocas combinaciones?

var q = from b in db.Bands 
join bm in db.BandMusicStyle on on b.BandId equals bm.BandId 
join ms in db.MusicStyle on bm.MusicStyleId equals m.MusicStyleId 
where b.Name.Contains(searchString) 
select new { b.Name, ms.ID, ms.Name, ms.Description }; 

o algo en ese sentido todos modos

+1

El problema es que Linq To Entities no le otorga propiedades para las claves externas en su tabla. Además, una tabla de enlace como BandMusicStyle no existe, ya que solo está ahí para vincular una Band y un MusicStyle entre sí. – Peter

+0

Ah, todavía estoy en el modo Sql de Linq –

+0

Oye, al menos ha resuelto el problema correctamente, lástima que no esté usando la tecnología que necesito ... – Peter

Cuestiones relacionadas