Cómo limitar una combinación externa izquierda LINQ a una fila

Tengo una combinación externa izquierda (abajo) que devuelve 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 por cada registro en ambas tablas, solo quiero ver un resultado de la tabla de la izquierda (elementos) sin importar cuántos resultados tenga en la tabla de la derecha (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 columnas de segunda identificación 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 solicité el plan, se demostró que la subconsulta se implementa mediante esta combinación:

      

    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 de si funcionará o qué tipo de wack SQL producirá 🙂

    Lo que quieres hacer es agrupar la tabla. 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() }; 

    Edit: habla David B Solo estoy haciendo esto porque Nick me lo pidió. Nick, modifica o elimina esta sección según lo consideres apropiado.

    El SQL generado es bastante grande. El int 0 (que se compara con el conteo) se pasa a través de un 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 uniones 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 para la eficiencia. Puede funcionar muy bien.