multiple left inner framework ejemplos conditions c# asp.net database linq join

c# - left - Cómo limitar un LINQ combinación externa izquierda a una fila



linq join c# ejemplos (3)

Tengo una combinación externa izquierda (abajo) que arroja los resultados como se esperaba. Necesito limitar los resultados de la tabla "derecha" al "primer" golpe. ¿Puedo hacer eso de alguna manera? Actualmente, obtengo un resultado para cada registro en ambas tablas, solo quiero ver un resultado de la tabla de la izquierda (ítems) sin importar cuántos resultados tenga en la tabla correcta (fotos).

var query = from i in db.items join p in db.photos on i.id equals p.item_id into tempPhoto from tp in tempPhoto.DefaultIfEmpty() orderby i.date descending select new { itemName = i.name, itemID = i.id, id = i.id, photoID = tp.PhotoID.ToString() }; GridView1.DataSource = query; GridView1.DataBind();


Esto hará el trabajo por ti.

from i in db.items let p = db.photos.Where(p2 => i.id == p2.item_id).FirstOrDefault() orderby i.date descending select new { itemName = i.name, itemID = i.id, id = i.id, photoID = p == null ? null : p.PhotoID.ToString(); }

Obtuve este sql cuando lo generé contra mi propio modelo (y sin el nombre y las segundas columnas de id en la proyección).

SELECT [t0].[Id] AS [Id], CONVERT(NVarChar,( SELECT [t2].[PhotoId] FROM ( SELECT TOP (1) [t1].[PhotoId] FROM [dbo].[Photos] AS [t1] WHERE [t1].[Item_Id] = ([t0].[Id]) ) AS [t2] )) AS [PhotoId] FROM [dbo].[Items] AS [t0] ORDER BY [t0].[Id] DESC

Cuando pregunté por el plan, mostró que la subconsulta se implementa mediante esta unión:

<RelOp LogicalOp="Left Outer Join" PhysicalOp="Nested Loops">


Lo que quieres hacer es agrupar la mesa. La mejor manera de hacer esto es:

var query = from i in db.items join p in (from p in db.photos group p by p.item_id into gp where gp.Count() > 0 select new { item_id = g.Key, Photo = g.First() }) on i.id equals p.item_id into tempPhoto from tp in tempPhoto.DefaultIfEmpty() orderby i.date descending select new { itemName = i.name, itemID = i.id, id = i.id, photoID = tp.Photo.PhotoID.ToString() };

Editar: Este es David B hablando. Solo estoy haciendo esto porque Nick me lo pidió. Nick, modifique o elimine esta sección como lo considere apropiado.

El SQL generado es bastante grande. El int 0 (para ser comparado con el recuento) se pasa a través del parámetro.

SELECT [t0].X AS [id], CONVERT(NVarChar(MAX),( SELECT [t6].Y FROM ( SELECT TOP (1) [t5].Y FROM [dbo].[Photos] AS [t5] WHERE (([t4].Y IS NULL) AND ([t5].Y IS NULL)) OR (([t4].Y IS NOT NULL) AND ([t5].Y IS NOT NULL) AND ([t4].Y = [t5].Y)) ) AS [t6] )) AS [PhotoId] FROM [dbo].[Items] AS [t0] CROSS APPLY (( SELECT NULL AS [EMPTY] ) AS [t1] OUTER APPLY ( SELECT [t3].Y FROM ( SELECT COUNT(*) AS [value], [t2].Y FROM [dbo].[Photos] AS [t2] GROUP BY [t2].Y ) AS [t3] WHERE (([t0].X) = [t3].Y) AND ([t3].[value] > @p0) ) AS [t4]) ORDER BY [t0].Z DESC

El plan de ejecución revela tres combinaciones a la izquierda. Al menos uno es trivial y no debe contarse (trae el cero). Hay suficiente complejidad aquí que no puedo señalar claramente ningún problema de eficiencia. Podría funcionar genial.


Podrías hacer algo como:

var q = from c in (from s in args select s).First() select c;

Alrededor de la última parte de la consulta. No estoy seguro si funcionará o qué tipo de SQL wack producirá :)