Generando un ÚNICO IFICENTE IZQUIERDO CON CUENTA EN LINQ A ENTIDADES -- sql campo con linq campo con linq-to-entities camp Relacionados El problema

Generating efficient LEFT JOIN with COUNT in Linq to Entities


2
vote

problema

Español

Tengo este esquema:

  Lists ( ListId, Name, DateCreated, ... ) ListItems( ListId, Text, Foo, Baz, Qux, ... )   

Tengo un IQueryable<List> que representa otra consulta LINQ que devuelve algunas entidades ScrollView0 .

Quiero ScrollView1 con algunos datos agregados de ScrollView2 , pero esto es difícil que Linq está generando un SQL ineficiente, pero también quiero hacer que la consulta sea compone.

Aquí hay algo similar al SQL, quiero linq para generar:

 SELECCIONE     * DE (     - Esta parte representa el iQeryable:      SELECCIONE         Listid,         Nombre,         ...     DE         Liza     Ordenar         Listas.DateCreated     COMPENSAR         0 filas Pasen solo 25 filas solo - Linq's .skip (0) .take (25) ) Como LISTSRESULT Únete a la izquierda (     - Esta es la consulta de datos agregados, quiero que Linq genere:     SELECCIONE         Listid,         Cuenta (1) como [cuenta],         Cuente (Caso cuando Foo = 'Bar' luego 1 el más Null End) como Countfoobar,         Cuente (Caso cuando Baz & GT; 5 entonces 1 más en el extremo nulo) como conteBAZ5     DE         Listita     DÓNDE         Qux no es nulo     AGRUPAR POR         Listado ) Como artículoStats en LISTRESULTS.LISTID = itemstats.listid 

Este es el linq que tengo, prefiero la sintaxis del método de extensión:

 Listas iQueryables = Getlists (0, 25);  VAR Stats = this.dbcontext.listitems     .Donde ((listitem li) = & gt; li.qux! = Nulo)     .Groupby ((listitem li) = & gt; li.listid)     .Seleccione (GRP = & gt; nuevo     {         GRP.KEY,         Count = GRP.COUNT (),         Countfoobar = GRP.COUNT ((LISTITEM LI) = & GT; LI.FOO == "BAR")         ConteBaz5 = GRP.COUNT ((LISTITEM LI) = & GT; LI.BAZ & GT; 5)     })  Listas de devolución     .Entrar(         Interno: estadísticas,         OUTERKEYSELECTOR: (LISTA L) = & GT; l.listid,         Innerkeyselector: GRP = & GT; GRP.KEY,         RESULTADOS DE RESULTADOS: (LISTA, DISCIONES DE IDENTOS) = & GT; New {LISTA, ITSETSTATS}     )  

Sin embargo, esto genera SQL que se ve así (esta consulta muestra mis nombres de mesa y columna real, que es un poco más complicada que el esquema que publiqué anteriormente :)

 SELECCIONE     [Proyecto13]. [C2] como [C1],     [Proyecto13]. [Listid] como [Listid],     [Proyecto13]. [C1] como [C2],     [Proyecto13]. [C3] como [C3],     [Proyecto13]. [C4] como [C4],     [Proyecto13]. [C5] como [C5],     [Proyecto13]. [C6] como [C6],     [Proyecto13]. [C7] como [C7]     De (seleccione         [Proyecto11]. [C1] como [C1],         [Proyecto11]. [Listid] como [Listid],         [Proyecto11]. [C2] como [C2],         [Proyecto11]. [C3] como [C3],         [Proyecto11]. [C4] como [C4],         [Proyecto11]. [C5] como [C5],         [Proyecto11]. [C6] como [C6],         (SELECCIONE             Cuenta (1) como [A1]             De (seleccione [Project12]. [Listid] como [Listid]                 De (seleccione                     [Extensión11]. [Listid] como [Listid],                     [Extensión11]. [Creado] como [creado]                     De [dbo]. [Listas] como [extensión11]                     Donde ([extensión11]. [Tenantid] = 8) y ([extensión11]. [BLARGHID] = 8)                 ) Como [Proyecto12]                 Orden por [Project12]. [Creado] Desc                 Offset 0 filas buscan solo 25 filas) como [Límite6]             Únase interno [DBO]. [Listitems] como [extensión12] en ([Límite6]. [Tenantid] = [extensión12]. [Tenantid]) y ([Límite6]. [BLARGHID] = [extensión12]) y ([Límite6]. [Listid] = [Extente12]. [Listid])             Donde (([extensión12]. [Baz] & gt; 0) o ((len ([extensión12]. [Notas]))) & gt; 0) o ((len ([extensión12]. [Valor]))) y gt; 0) ) Y ([Proyecto11]. [Tenantid] = [extensión12]. [Tenantid]) y ([Proyecto11]. [BLARGHID] = [extensión12]. [BLARGHID]) y ([Proyecto11]. [Listid] = [Extente12] . [Listid]) y ([extensión12]. [RecomendaciónRevisión] no es nula)) como [C7]         De (seleccione             [Proyecto9]. [C1] como [C1],             [Proyecto9]. [Tenantid] como [Tenantid],             [Proyecto9]. [BLARGHID] como [BLARGHID],             [Project9]. [Listid] como [Listid],             [Proyecto9]. [C2] como [C2],             [Proyecto9]. [C3] como [C3],             [Proyecto9]. [C4] como [C4],             [Proyecto9]. [C5] como [C5],             (SELECCIONE                 Cuenta (1) como [A1]                 De (seleccione [Project10]. [Tenantid] como [Tenantid], [Project10]. [BLARGHID] como [BLARGHID], [Project10]. [Listid] como [Listid]                     De (seleccione                         [Extensión9]. [Tenantid] como [Tenantid],                         [Extensión9]. [BLARGHID] como [BLARGHID],                         [Extensión9]. [Listid] como [Listid],                         [Extensión9]. [Creado] como [creado]                         De [dbo]. [Listas] como [extensión9] Donde ([extensión9]. [Tenantid] = 8) y ([extensión9]. [BLARGHID] = 8)                     ) Como [Proyecto10]                     Orden por [Project10]. [Creado] Desc                     Offset 0 filas buscan solo 25 filas) como [Límite5]                 Únase interno [DBO]. [Listitems] como [extensión10] en ([Límite5]. [Tenantid] = [extensión10]. [Tenantid]) y ([Límite5]. [BLARGHID] = [extensión10]. ([Límite5]. [Listid] = [extensión10]. [Listid])                 Donde (([extensión10]. [Baz] & gt; 0) o ((len ([extensión10]. [Notas])) & gt; 0) o ((len (len (extensión10]. [Valor])) y gt; 0) ) Y ([Project9]. [Tenantid] = [extensión10]. [Tenantid]) y ([Proyecto9]. [BLARGHID] = [extensión10]. [BLARGHID]) y ([Proyecto9]. [Listid] = [Extente10] . [LISTID]) y (3 = [extensión10]. [BAZ])) como [C6]             De (seleccione                 [Proyecto7]. [C1] como [C1],                 [Proyecto7]. [Tenantid] como [Tenantid],                 [Proyecto7]. [BLARGHID] como [BLARGHID],                 [Proyecto7]. [Listid] como [Listid],                 [Proyecto7]. [C2] como [C2],                 [Proyecto7]. [C3] como [C3],                 [Proyecto7]. [C4] como [C4],                 (SELECCIONE                     Cuenta (1) como [A1]                     De (seleccione [Project8]. [Tenantid] como [Tenantid], [Proyecto8]. [BLARGHID] como [BLARGHID], [Proyecto8]. [Listid] como [Listid]                         De (seleccione                             [Extensión7]. [Tenantid] como [Tenantid],                             [Extente7]. [BLARGHID] como [BLARGHID],                             [Extente7]. [Listid] como [Listid],                             [Extensión7]. [Creado] como [creado]                             De [dbo]. [Listas] como [extensión7]                             Donde ([extensión7]. [Tenantid] = 8) y ([extensión7]. [BLARGHID] = 8)                         ) Como [Proyecto8]                         Orden por [Project8]. [Creado] Desc                         Offset 0 filas buscan solo 25 filas) como [Límite4]                     Únase interno [DBO]. [Listitems] como [extensión8] en ([Límite4]. [Tenantid] = [Extente8]. [Tenantid]) y ([Límite4]. [BLARGHID] = [Extente8]) y ([Límite4]. [Listid] = [Extente8]. [Listid])                     Donde (([extensión8]. [Baz] & gt; 0) o ((len ([extensión8]. [Notas])) & gt; 0) o ((len (len ([extensión8]. [Valor])) y gt; 0) ) Y ([Proyecto7]. [Tenantid] = [extensión8]. [Tenantid]) y ([Proyecto7]. [BLARGHID] = [extensión8]. [BLARGHID]) y ([Proyecto7]. [Listid] = [Extente8] . [Listid]) y (2 = [extensión8]. [Baz]) como [C5]                 De (seleccione                     [Proyecto5]. [C1] como [C1],                     [Proyecto5]. [Tenantid] como [Tenantid],                     [Proyecto5]. [BLARGHID] como [BLARGHID],                     [Proyecto5]. [Listid] como [Listid],                     [Proyecto5]. [C2] como [C2],                     [Proyecto5]. [C3] como [C3],                     (SELECCIONE                         Cuenta (1) como [A1]                         De (seleccione [Project6]. [Tenantid] como [Tenantid], [Proyecto6]. [BLARGHID] como [BLARGHID], [Proyecto6]. [Listid] como [Listid]                             De (seleccione                                 [Extensión5]. [Tenantid] como [Tenantid],                                 [Extente5]. [BLARGHID] como [BLARGHID],                                 [Extensión5]. [Listid] como [Listid],                                 [Extensión5]. [Creado] como [creado]                                 De [dbo]. [Listas] como [extensión5]                                 Donde ([extensión5]. [Tenantid] = 8) y ([extensión5]. [BLARGHID] = 8)                             ) Como [Proyecto6]                             Orden por [Project6]. [Creado] Desc                             Offset 0 filas buscan solo 25 filas) como [Límite3]                         ÚNEÑA INTERNA [DBO]. [LISTITIMES] AS [EXTENT 6] ON ([Límite3]. [Tenantid] = [extensión6]. [Tenantid]) y ([Límite3]. [BLARGHID] = [extensión]. [BLARGHID]) y ([Límite3]. [Listid] = [extensión6]. [Listid])                         Donde (([extensión6]. [Baz] & gt; 0) o ((len ([extensión6]. [Notas])) & gt; 0) o ((len ([extensión6]. [Valor]))) ) Y ([Project5]. [Tenantid] = [Extente6]. [Tenantid]) y ([Proyecto5]. [BLARGHID] = [extensión6]. [BLARGHID]) y ([Proyecto5]. [Listid] = [Extente6] . [LISTID]) y (1 = [extensión6]. [BAZ])) como [C4]                     De (seleccione                         [Proyecto3]. [C1] como [C1],                         [Proyecto3]. [Tenantid] como [Tenantid],                         [Proyecto3]. [BLARGHID] como [BLARGHID],                         [Proyecto3]. [Listid] como [Listid],                         [Proyecto3]. [C2] como [C2],                         (SELECCIONE                             Cuenta (1) como [A1]                             De (seleccione [Project4]. [Tenantid] como [Tenantid], [Proyecto4]. [BLARGHID] como [BLARGHID], [Proyecto4]. [Listid] como [Listid]                                 De (seleccione [Extensión3]. [Tenantid] como [Tenantid],                                     [Extensión3]. [BLARGHID] como [BLARGHID],                                     [Extensión3]. [Listid] como [Listid],                                     [Extensión3]. [Creado] como [creado]                                     De [DBO]. [Listas] como [extensión3]                                     Donde ([extensión3]. [Tenantid] = 8) y ([extensión3]. [BLARGHID] = 8)                                 ) Como [Proyecto4]                                 Orden por [Project4]. [Creado] Desc                                 Offset 0 filas buscan solo 25 filas) como [Límite2]                             ÚNEÑA INTERNA [DBO]. [Listitems] como [extensión4] en ([Límite2]. [Tenantid] = [Extente4]. [Tenantid]) y ([Límite2]. [BLARGHID] = [extensión]. [BLARGHID]) y ([Límite2]. [Listid] = [Extente4]. [Listid])                             Donde (([extensión4]. [Baz] & gt; 0) o ((len ([extensión4]. [Notas])) & gt; 0) o ((len ([extensión4]. [Valor]))) ) Y ([Proyecto3]. [Tenantid] = [extensión4]. [Tenantid]) y ([Proyecto3]. [BLARGHID] = [extensión4]. [BLARGHID]) y ([Proyecto3]. [Listid] = [Extent4] . [LISTID]) y ([Extente4]. [Foo] = 1)) como [C3]                         De (seleccione                             [Groupby1]. [A1] como [C1],                             [Groupby1]. [K1] como [Tenantid],                             [Groupby1]. [K2] como [BLARGHID],                             [Groupby1]. [K3] como [Listid],                             [Groupby1]. [K4] como [C2]                             De (seleccione                                 [Proyecto2]. [K1] como [K1],                                 [Proyecto2]. [K2] como [K2],                                 [Proyecto2]. [K3] como [K3],                                 [Proyecto2]. [K4] como [K4],                                 Cuenta ([Project2]. [A1]) como [A1]                                 De (seleccione                                     [Proyecto2]. [Tenantid] como [K1],                                     [Proyecto2]. [BLARGHID] como [K2],                                     [Proyecto2]. [Listid] como [K3],                                     1 como [K4],                                     1 como [A1]                                     De (seleccione                                         [Extente2]. [Listid] como [Listid]                                         De (seleccione [Project1]. [Listid] como [Listid]                                             De (seleccione                                                 [Extente1]. [Listid] como [Listid],                                                 [Extensión1]. [Creado] como [creado]                                                 Desde [dbo]. [Listas] como [extensión1]                                                 Donde ([extensión1]. [Tenantid] = 8) y ([Extente1]. [BLARGHID] = 8)                                             ) Como [Proyecto1]                                             Orden por [Project1]. [Creado] Desc                                             Offset 0 filas buscan solo 25 filas) como [Límite1]                                         Únase interno [DBO]. [Listitems] como [extensión2] en (([Límite1]. [Listid] = [Extente2]. [Listid])                                         Donde ([extensión2]. [Baz] & gt; 0) o ((len ([extensión2]. [Notas])) & gt; 0) o ((len ([extensión2]. [Valor])) y gt; 0)                                     ) Como [Proyecto2]                                 ) Como [Proyecto2]                                 Grupo por [k1], [k2], [k3], [k4]                             ) Como [groupby1]                         ) Como [Proyecto3]                     ) Como [Proyecto5]                 ) Como [Proyecto7]             ) Como [Proyecto9]         ) Como [Proyecto11]     ) Como [Proyecto13] 

No compone las declaraciones ScrollView3 en absoluto, y se mueve el 99887776614 PREDICATES para separar ScrollView515 CLAUSES. También tenga en cuenta las subconsferencias paginadas repetidas (donde se usa ScrollView6 ), mientras que mi consulta a mano solo lo ejecuta una vez.

Original en ingles

I have this schema:

Lists ( ListId, Name, DateCreated, ... ) ListItems( ListId, Text, Foo, Baz, Qux, ... ) 

I have an IQueryable<List> which represents another Linq query which returns some List entities.

I want to JOIN it with some aggregate data of ListItems, but this proving difficult as Linq is generating inefficient SQL - but I also want to make the query composable.

Here is something similar to the SQL I want Linq to generate:

 SELECT     * FROM (     -- This part represents the IQueryable:      SELECT         ListId,         Name,         ...     FROM         Lists     ORDER BY         Lists.DateCreated     OFFSET         0 ROWS FETCH NEXT 25 ROWS ONLY -- Linq's .Skip(0).Take(25) ) AS ListsResult LEFT JOIN (     -- This is the aggregate data query I want Linq to generate:     SELECT         ListId,         COUNT(1) AS [Count],         COUNT( CASE WHEN Foo = 'bar' THEN 1 ELSE NULL END ) AS CountFooBar,         COUNT( CASE WHEN Baz > 5     THEN 1 ELSE NULL END ) AS CountBaz5     FROM         ListItems     WHERE         Qux IS NOT NULL     GROUP BY         ListId ) AS ItemsStats ON ListResults.ListId = ItemsStats.ListId 

This is the Linq I have - I prefer the Extension Method syntax:

 IQueryable lists = GetLists( 0, 25 );  var stats = this.dbContext.ListItems     .Where( (ListItem li) => li.Qux != null )     .GroupBy( (ListItem li) => li.ListId )     .Select( grp => new     {         grp.Key,         Count       = grp.Count(),         CountFooBar = grp.Count( (ListItem li) => li.Foo == "bar" )         CountBaz5   = grp.Count( (ListItem li) => li.Baz  > 5 )     } )  return lists     .Join(         inner: stats,         outerKeySelector: (List l) => l.ListId,         innerKeySelector: grp => grp.Key,         resultSelector: (list, itemStats) => new { list, itemsStats }     )  

However this generates SQL looking like this (this query shows my real table and column names, which is a bit more complicated than the schema I posted earlier:)

 SELECT      [Project13].[C2] AS [C1],      [Project13].[ListId] AS [ListId],      [Project13].[C1] AS [C2],      [Project13].[C3] AS [C3],      [Project13].[C4] AS [C4],      [Project13].[C5] AS [C5],      [Project13].[C6] AS [C6],      [Project13].[C7] AS [C7]     FROM ( SELECT          [Project11].[C1] AS [C1],          [Project11].[ListId] AS [ListId],          [Project11].[C2] AS [C2],          [Project11].[C3] AS [C3],          [Project11].[C4] AS [C4],          [Project11].[C5] AS [C5],          [Project11].[C6] AS [C6],          (SELECT              COUNT(1) AS [A1]             FROM   (SELECT [Project12].[ListId] AS [ListId]                 FROM ( SELECT                      [Extent11].[ListId] AS [ListId],                      [Extent11].[Created] AS [Created]                     FROM [dbo].[Lists] AS [Extent11]                     WHERE ([Extent11].[TenantId] = 8) AND ([Extent11].[BlarghId] = 8)                 )  AS [Project12]                 ORDER BY [Project12].[Created] DESC                 OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit6]             INNER JOIN [dbo].[ListItems] AS [Extent12] ON ([Limit6].[TenantId] = [Extent12].[TenantId]) AND ([Limit6].[BlarghId] = [Extent12].[BlarghId]) AND ([Limit6].[ListId] = [Extent12].[ListId])             WHERE (([Extent12].[Baz] > 0) OR ((LEN([Extent12].[Notes])) > 0) OR ((LEN([Extent12].[Value])) > 0)) AND ([Project11].[TenantId] = [Extent12].[TenantId]) AND ([Project11].[BlarghId] = [Extent12].[BlarghId]) AND ([Project11].[ListId] = [Extent12].[ListId]) AND ([Extent12].[RecommendationRevision] IS NOT NULL)) AS [C7]         FROM ( SELECT              [Project9].[C1] AS [C1],              [Project9].[TenantId] AS [TenantId],              [Project9].[BlarghId] AS [BlarghId],              [Project9].[ListId] AS [ListId],              [Project9].[C2] AS [C2],              [Project9].[C3] AS [C3],              [Project9].[C4] AS [C4],              [Project9].[C5] AS [C5],              (SELECT                  COUNT(1) AS [A1]                 FROM   (SELECT [Project10].[TenantId] AS [TenantId], [Project10].[BlarghId] AS [BlarghId], [Project10].[ListId] AS [ListId]                     FROM ( SELECT                          [Extent9].[TenantId] AS [TenantId],                          [Extent9].[BlarghId] AS [BlarghId],                          [Extent9].[ListId] AS [ListId],                          [Extent9].[Created] AS [Created]                         FROM [dbo].[Lists] AS [Extent9]                         WHERE ([Extent9].[TenantId] = 8) AND ([Extent9].[BlarghId] = 8)                     )  AS [Project10]                     ORDER BY [Project10].[Created] DESC                     OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit5]                 INNER JOIN [dbo].[ListItems] AS [Extent10] ON ([Limit5].[TenantId] = [Extent10].[TenantId]) AND ([Limit5].[BlarghId] = [Extent10].[BlarghId]) AND ([Limit5].[ListId] = [Extent10].[ListId])                 WHERE (([Extent10].[Baz] > 0) OR ((LEN([Extent10].[Notes])) > 0) OR ((LEN([Extent10].[Value])) > 0)) AND ([Project9].[TenantId] = [Extent10].[TenantId]) AND ([Project9].[BlarghId] = [Extent10].[BlarghId]) AND ([Project9].[ListId] = [Extent10].[ListId]) AND (3 = [Extent10].[Baz])) AS [C6]             FROM ( SELECT                  [Project7].[C1] AS [C1],                  [Project7].[TenantId] AS [TenantId],                  [Project7].[BlarghId] AS [BlarghId],                  [Project7].[ListId] AS [ListId],                  [Project7].[C2] AS [C2],                  [Project7].[C3] AS [C3],                  [Project7].[C4] AS [C4],                  (SELECT                      COUNT(1) AS [A1]                     FROM   (SELECT [Project8].[TenantId] AS [TenantId], [Project8].[BlarghId] AS [BlarghId], [Project8].[ListId] AS [ListId]                         FROM ( SELECT                              [Extent7].[TenantId] AS [TenantId],                              [Extent7].[BlarghId] AS [BlarghId],                              [Extent7].[ListId] AS [ListId],                              [Extent7].[Created] AS [Created]                             FROM [dbo].[Lists] AS [Extent7]                             WHERE ([Extent7].[TenantId] = 8) AND ([Extent7].[BlarghId] = 8)                         )  AS [Project8]                         ORDER BY [Project8].[Created] DESC                         OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit4]                     INNER JOIN [dbo].[ListItems] AS [Extent8] ON ([Limit4].[TenantId] = [Extent8].[TenantId]) AND ([Limit4].[BlarghId] = [Extent8].[BlarghId]) AND ([Limit4].[ListId] = [Extent8].[ListId])                     WHERE (([Extent8].[Baz] > 0) OR ((LEN([Extent8].[Notes])) > 0) OR ((LEN([Extent8].[Value])) > 0)) AND ([Project7].[TenantId] = [Extent8].[TenantId]) AND ([Project7].[BlarghId] = [Extent8].[BlarghId]) AND ([Project7].[ListId] = [Extent8].[ListId]) AND (2 = [Extent8].[Baz])) AS [C5]                 FROM ( SELECT                      [Project5].[C1] AS [C1],                      [Project5].[TenantId] AS [TenantId],                      [Project5].[BlarghId] AS [BlarghId],                      [Project5].[ListId] AS [ListId],                      [Project5].[C2] AS [C2],                      [Project5].[C3] AS [C3],                      (SELECT                          COUNT(1) AS [A1]                         FROM   (SELECT [Project6].[TenantId] AS [TenantId], [Project6].[BlarghId] AS [BlarghId], [Project6].[ListId] AS [ListId]                             FROM ( SELECT                                  [Extent5].[TenantId] AS [TenantId],                                  [Extent5].[BlarghId] AS [BlarghId],                                  [Extent5].[ListId] AS [ListId],                                  [Extent5].[Created] AS [Created]                                 FROM [dbo].[Lists] AS [Extent5]                                 WHERE ([Extent5].[TenantId] = 8) AND ([Extent5].[BlarghId] = 8)                             )  AS [Project6]                             ORDER BY [Project6].[Created] DESC                             OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit3]                         INNER JOIN [dbo].[ListItems] AS [Extent6] ON ([Limit3].[TenantId] = [Extent6].[TenantId]) AND ([Limit3].[BlarghId] = [Extent6].[BlarghId]) AND ([Limit3].[ListId] = [Extent6].[ListId])                         WHERE (([Extent6].[Baz] > 0) OR ((LEN([Extent6].[Notes])) > 0) OR ((LEN([Extent6].[Value])) > 0)) AND ([Project5].[TenantId] = [Extent6].[TenantId]) AND ([Project5].[BlarghId] = [Extent6].[BlarghId]) AND ([Project5].[ListId] = [Extent6].[ListId]) AND (1 = [Extent6].[Baz])) AS [C4]                     FROM ( SELECT                          [Project3].[C1] AS [C1],                          [Project3].[TenantId] AS [TenantId],                          [Project3].[BlarghId] AS [BlarghId],                          [Project3].[ListId] AS [ListId],                          [Project3].[C2] AS [C2],                          (SELECT                              COUNT(1) AS [A1]                             FROM   (SELECT [Project4].[TenantId] AS [TenantId], [Project4].[BlarghId] AS [BlarghId], [Project4].[ListId] AS [ListId]                                 FROM ( SELECT                                      [Extent3].[TenantId] AS [TenantId],                                      [Extent3].[BlarghId] AS [BlarghId],                                      [Extent3].[ListId] AS [ListId],                                      [Extent3].[Created] AS [Created]                                     FROM [dbo].[Lists] AS [Extent3]                                     WHERE ([Extent3].[TenantId] = 8) AND ([Extent3].[BlarghId] = 8)                                 )  AS [Project4]                                 ORDER BY [Project4].[Created] DESC                                 OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit2]                             INNER JOIN [dbo].[ListItems] AS [Extent4] ON ([Limit2].[TenantId] = [Extent4].[TenantId]) AND ([Limit2].[BlarghId] = [Extent4].[BlarghId]) AND ([Limit2].[ListId] = [Extent4].[ListId])                             WHERE (([Extent4].[Baz] > 0) OR ((LEN([Extent4].[Notes])) > 0) OR ((LEN([Extent4].[Value])) > 0)) AND ([Project3].[TenantId] = [Extent4].[TenantId]) AND ([Project3].[BlarghId] = [Extent4].[BlarghId]) AND ([Project3].[ListId] = [Extent4].[ListId]) AND ([Extent4].[Foo] = 1)) AS [C3]                         FROM ( SELECT                              [GroupBy1].[A1] AS [C1],                              [GroupBy1].[K1] AS [TenantId],                              [GroupBy1].[K2] AS [BlarghId],                              [GroupBy1].[K3] AS [ListId],                              [GroupBy1].[K4] AS [C2]                             FROM ( SELECT                                  [Project2].[K1] AS [K1],                                  [Project2].[K2] AS [K2],                                  [Project2].[K3] AS [K3],                                  [Project2].[K4] AS [K4],                                  COUNT([Project2].[A1]) AS [A1]                                 FROM ( SELECT                                      [Project2].[TenantId] AS [K1],                                      [Project2].[BlarghId] AS [K2],                                      [Project2].[ListId] AS [K3],                                      1 AS [K4],                                      1 AS [A1]                                     FROM ( SELECT                                          [Extent2].[ListId] AS [ListId]                                         FROM   (SELECT [Project1].[ListId] AS [ListId]                                             FROM ( SELECT                                                  [Extent1].[ListId] AS [ListId],                                                  [Extent1].[Created] AS [Created]                                                 FROM [dbo].[Lists] AS [Extent1]                                                 WHERE ([Extent1].[TenantId] = 8) AND ([Extent1].[BlarghId] = 8)                                             )  AS [Project1]                                             ORDER BY [Project1].[Created] DESC                                             OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit1]                                         INNER JOIN [dbo].[ListItems] AS [Extent2] ON (([Limit1].[ListId] = [Extent2].[ListId])                                         WHERE ([Extent2].[Baz] > 0) OR ((LEN([Extent2].[Notes])) > 0) OR ((LEN([Extent2].[Value])) > 0)                                     )  AS [Project2]                                 )  AS [Project2]                                 GROUP BY [K1], [K2], [K3], [K4]                             )  AS [GroupBy1]                         )  AS [Project3]                     )  AS [Project5]                 )  AS [Project7]             )  AS [Project9]         )  AS [Project11]     )  AS [Project13] 

It doesn't compose the COUNT() statements together at all, and it moves the COUNT predicates to separate WHERE clauses. Also note the repeated paged subqueries (where OFFSET 0 ROW FETCH NEXT 25 is used) whereas my hand-written query only executes it once.

        

Lista de respuestas

1
 
vote

Aquí hay una semi-solución que tengo:

Me di cuenta de que la mejor solución a corto plazo es tener el SQL en la base de datos (como un udf lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 2 o 99887776613 ), esto significaría que algún código de datos lo haría Por lo tanto, tienen que estar en la base de datos (en lugar de usar el DB como "Tienda Dumb").

Primero creé un UDF valorado por la tabla que aceptaría un parámetro vallado de mesa, el razonamiento que permitiría la composición, al costo de la necesidad de generar la tabla de parámetros de entrada (una matriz de lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 4 valores de la consulta paginada). Sin embargo, al hacerlo, me di cuenta de que Linq-to-entidades (versión 6) no admite los parámetros valorados en la tabla en las importaciones de funciones todavía.

Luego razoné un mejor enfoque sería mover el funcionamiento lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 515 a un lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 6616 (que representa la mitad del lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 7 que tenía En mi consulta escrita a mano), y luego puedo obtener LINQ para unirse a la contra el lambda618 existente, conservando la composición y generando una consulta eficiente de tiempo de ejecución (de hecho, cuando lo ejecuto, la consulta toma 34 ms Para ejecutar de acuerdo con el perfilador de SQL Server, mientras que la vieja consulta ineficiente generada por Linq tomó 830ms).

Aquí está lo que usé:

 Crear Listitemstatisticstatistics  SELECCIONE     Listid,      Cuenta (*) como [RIGETL],     Cuente (caso cuando ...) como cuenta ...  DE     Listita DÓNDE     Foo = 'bar' AGRUPAR POR      Listado 

y luego desde dentro de linq:

 Listas iQeryables = GetListsQuy (0, 25);  var listswithitemsstats = listas.     .Entrar(         Interno: esta.dbcontext.listitemstatistics,         OperkeySelector: LISTA = & GT; list.listid,         InnerkeySelector: Fila = & gt; Row.listid,         ClaroSelector: (Lista, fila) = & gt; nuevo {lista, fila}     ) 

Sin embargo, debido a que esto utiliza la lógica del lado de la base de datos (en el lambdas_list = [ (lambda a: lambda: a.some_var)(o) for o in obj_list ] 9 ) no es ideal.

 

Here's a semi-workaround I have:

I realised the best short-term solution is to have the SQL in the database (as a UDF FUNCTION or VIEW), this would mean that some data code would therefore have to be in the database (rather than using the DB as a "dumb store").

I first created a table-valued UDF which would accept a table-valued parameter, reasoning that would allow for composition, at the cost of needing to generate the input parameter table (an array of ListId values from the paged query). However in doing so, I realised that Linq-to-Entities (version 6) does not support table-valued parameters in Function Imports yet.

I then reasoned a better approach would be to move the COUNT operation to a VIEW (which represents one half of the LEFT JOIN I had in my hand-written query), and then I can get Linq to JOIN that against the existing IQueryable, thus retaining composability and generating an efficient runtime query (indeed, when I run it, the query takes 34ms to execute according to SQL Server Profiler, whereas the old Linq-generated inefficient query took 830ms).

Here's what I used:

 CREATE VIEW ListItemStatistics AS  SELECT     ListId,      COUNT(*) AS [CountAll],     COUNT( CASE WHEN ... ) AS Count...  FROM     ListItems WHERE     Foo = 'bar' GROUP BY      ListId 

And then from within Linq:

 IQueryable lists = GetListsQuery( 0, 25 );  var listsWithItemsStats = lists.     .Join(         inner: this.dbContext.ListItemStatistics,         outerKeySelector: list => list.ListId,         innerKeySelector: row => row.ListId,         resultSelector: (list,row) => new { list, row }     ); 

However because this does use database-side logic (in the VIEW) it is not ideal.

 
 
1
 
vote

En mi experiencia, la EF genera tales consultas cuando usa funciones agregadas que aplican el filtrado como obj0 ) en su caso. Obtendrá una consulta de SQL mucho mejor si reemplaza obj1 Constructo con suma condicional ( 99887776622 ) como este:

  obj3  

Las otras partes se mantienen igual. Antes de la modificación de MOD recibí SQL similar a los publicados, y aquí está lo que estoy recibiendo después de este pequeño mod:

  obj4  

Actualizar: El anterior es solo el equivalente de LINQ de su consulta de SQL manual (cuando ajusta el código de unión para producir obj5 ). Sin embargo, teniendo en cuenta la paginación de datos maestros, 99887776626 QUERÍA SQL puede funcionar mejor. Puede dejar que Linq a entidades genere dicho tipo de consulta como esta:

  obj7  
 

In my experience EF generates such queries when you use aggregate functions that apply filtering like Count(predicate) in your case. You'll get much better SQL query if you replace Count(condition) construct with conditional sum (Sum(condition ? 1 : 0)) like this:

var stats = db.ListItems     .Where(li => li.Qux != null)     .GroupBy(li => li.ListId)     .Select(grp => new     {         grp.Key,         Count = grp.Count(),         CountFooBar = grp.Sum(li => li.Foo == "bar" ? 1 : 0),         CountBaz5 = grp.Sum(li => li.Baz > 5 ? 1 : 0)     }); 

The other parts stay the same. Before the mod I was getting similar SQL to the posted, and here is what I'm getting after this little mod:

SELECT      [Limit1].[ListId] AS [ListId],      [Limit1].[Name] AS [Name],      [Limit1].[DateCreated] AS [DateCreated],      [GroupBy1].[K1] AS [ListId1],      [GroupBy1].[A1] AS [C1],      [GroupBy1].[A2] AS [C2],      [GroupBy1].[A3] AS [C3]     FROM   (SELECT [Extent1].[ListId] AS [ListId], [Extent1].[Name] AS [Name], [Extent1].[DateCreated] AS [DateCreated]         FROM [dbo].[List] AS [Extent1]         ORDER BY [Extent1].[DateCreated] ASC         OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY  ) AS [Limit1]     INNER JOIN  (SELECT          [Filter1].[K1] AS [K1],          COUNT([Filter1].[A1]) AS [A1],          SUM([Filter1].[A2]) AS [A2],          SUM([Filter1].[A3]) AS [A3]         FROM ( SELECT              [Extent2].[ListId] AS [K1],              1 AS [A1],              CASE WHEN (N'bar' = [Extent2].[Foo]) THEN 1 ELSE 0 END AS [A2],              CASE WHEN ([Extent2].[Baz] > 5) THEN 1 ELSE 0 END AS [A3]             FROM [dbo].[ListItem] AS [Extent2]             WHERE [Extent2].[Qux] IS NOT NULL         )  AS [Filter1]         GROUP BY [K1] ) AS [GroupBy1] ON [Limit1].[ListId] = [GroupBy1].[K1] 

UPDATE: The above is just the LINQ equivalent of your manual SQL query (when you adjust the join code to produce LEFT OUTER JOIN). However, taking into account the master data paging, OUTER APPLY SQL query might perform better. You can let LINQ to Entities generate such type of query like this:

var listsWithItemsStats = lists     .SelectMany(l => db.ListItems         .Where(li => li.ListId == l.ListId && li.Qux != null)         .GroupBy(li => li.ListId)         .Select(grp => new         {             grp.Key,             Count = grp.Count(),             CountFooBar = grp.Sum(li => li.Foo == "bar" ? 1 : 0),             CountBaz5 = grp.Sum(li => li.Baz > 5 ? 1 : 0)         })         .DefaultIfEmpty(),         (list, itemsStats) => new { list, itemsStats }); 
 
 
   
   

Relacionados problema

3  ¿Cómo mejoraría esta consulta LINQ de 7 líneas que actúa como una especificación?  ( How would i improve this 7 line linq query that acts as a specification ) 
BigQuery en la parte superior obtiene un conjunto de productos y tablas relacionadas con anidadas. Luego, aplico filtrado en un mal intento de un patrón de es...

16  ¿Cuál es el mejor libro para aprender LINQ, incluido LINQ a las entidades? [cerrado]  ( Which is the best book out there to learn linq including linq to entities ) 
cerrado. Esta pregunta no cumple con pautas de desbordamiento de pila . Actualmente no está aceptando respuestas. ...

1  Llene la vista al pasar un param usando LINQ a EF  ( Fill view when passing a param using linq to ef ) 
El siguiente código está funcionando .. El customview se llena sin ningún error. customview public static ProductView CustomView(Product data) { va...

1  ¿Cómo tomar valores MIN / MAX para columnas adyacentes después de agrupar en LINQ?  ( How to take min max values for adjacent columns after grouping in linq ) 
chicos, soy novato a linq. Amablemente ayúdame A continuación se encuentra mi escenario ... ParaId-------ErrorId 1-------------1 60------------2 125-------...

2  Simplifica que esta propiedad se use en un predicado  ( Simplify this property to be used in a predicate ) 
Tengo muchos public function prepareGridVisualElement(grid:Grid, rowIndex:int, columnIndex:int):void { const dataGrid:DataGrid = grid.dataGrid; if (!...

2  Consulta de construcción dinámica para EF4 usando árboles de expresión, NotsUpPortedException  ( Dynamically building query for ef4 using expression trees notsupportedexception ) 
Estoy intentando construir un árbol de expresión para realizar una consulta LINQ a entidades en .NET 4.0 con EF4. Cuando intento ejecutar la consulta que he c...

0  Linq Query decimal y devolver decimal convertido a cadena  ( Linq query decimal and return decimal converted to string ) 
Tratando de usar LINQ para consultar un total de pedido y devolverlo de nuevo como una etiqueta.Text en ASP.NET Carga de página: IQueryable<decimal> Orde...

0  Clasificación de linq, no funciona  ( Linq sorting doesnt work ) 
Tengo una consulta LINQ como esta: from i in _db.Items.OfType<Medium>() from m in i.Modules from p in m.Pages where i != null && i.Type == 1 && i.Published...

1  Ajax Control Toolkit Autocompletar Extender no funciona  ( Ajax control toolkit autocomplete extender not working ) 
No puedo obtener AJAX CT AUTOCOMPLETLE para trabajar. El problema es cuando empiezo a escribir en el cuadro de texto no pasa nada. El problema de la frist que...

0  Marco de entidad a LINQ Búsqueda de fecha  ( Entity framework to linq date search ) 
Estoy tratando de crear una consulta de EF a Linq, donde necesito sumar una propiedad por cada día de la semana, una suma de todos los registros el lunes, lue...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos