Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

LINQ to SQL Take sem pular causa várias instruções SQL


Primeiro - algum raciocínio para o bug Take.

Se você simplesmente pegar , o tradutor de consultas usa apenas top. O Top10 não dará a resposta certa se a cardinalidade for quebrada ao ingressar em uma coleção filha. Portanto, o tradutor de consulta não se junta à coleção filho (em vez disso, ele repete a consulta para os filhos).

Se você Pular e pegar , então o tradutor de consulta entra em ação com alguma lógica RowNumber sobre as linhas pai ... esses números de linha permitem que sejam 10 pais, mesmo que sejam realmente 50 registros devido a cada pai ter 5 filhos.

Se você Pular(0) e Pegar , Skip é removido como uma não operação pelo tradutor - é como se você nunca tivesse dito Skip.

Este será um salto conceitual difícil de onde você está (chamando Skip and Take) para uma "solução simples". O que precisamos fazer - é forçar a tradução a ocorrer em um ponto em que o tradutor não possa remover Skip(0) como uma não operação. Precisamos ligar para Skip e fornecer o número ignorado posteriormente.
DataClasses1DataContext myDC = new DataClasses1DataContext();
  //setting up log so we can see what's going on
myDC.Log = Console.Out;

  //hierarchical query - not important
var query = myDC.Options.Select(option => new{
  ID = option.ParentID,
  Others = myDC.Options.Select(option2 => new{
    ID = option2.ParentID
  })
});
  //request translation of the query!  Important!
var compQuery = System.Data.Linq.CompiledQuery
  .Compile<DataClasses1DataContext, int, int, System.Collections.IEnumerable>
  ( (dc, skip, take) => query.Skip(skip).Take(take) );

  //now run the query and specify that 0 rows are to be skipped.
compQuery.Invoke(myDC, 0, 10);

Isso produz a seguinte consulta:
SELECT [t1].[ParentID], [t2].[ParentID] AS [ParentID2], (
    SELECT COUNT(*)
    FROM [dbo].[Option] AS [t3]
    ) AS [value]
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ID]) AS [ROW_NUMBER], [t0].[ParentID]
    FROM [dbo].[Option] AS [t0]
    ) AS [t1]
LEFT OUTER JOIN [dbo].[Option] AS [t2] ON 1=1 
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p1 + @p2
ORDER BY [t1].[ROW_NUMBER], [t2].[ID]
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [0]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [0]
-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [10]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1

E é aqui que ganhamos!
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p1 + @p2