Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

LINQ to SQL Take w/o Skip provoque plusieurs instructions SQL

Tout d'abord - un raisonnement pour le bogue Take.

Si vous prenez simplement , le traducteur de requête utilise simplement top. Top10 ne donnera pas la bonne réponse si la cardinalité est brisée en se joignant à une collection enfant. Ainsi, le traducteur de requêtes ne se joint pas à la collection enfant (au lieu de cela, il interroge les enfants).

Si vous Sautez et prenez , puis le traducteur de requête entre en jeu avec une logique RowNumber sur les lignes parentes... ces numéros de ligne lui permettent de prendre 10 parents, même s'il s'agit en réalité de 50 enregistrements car chaque parent a 5 enfants.

Si vous Passez (0) et prenez , Skip est supprimé en tant que non-opération par le traducteur - c'est comme si vous n'aviez jamais dit Skip.

Cela va être un saut conceptuel difficile d'où vous êtes (en appelant Skip and Take) à une "solution de contournement simple". Ce que nous devons faire, c'est forcer la traduction à se produire à un point où le traducteur ne peut pas supprimer Skip(0) en tant que non-opération. Nous devons appeler Skip et fournir le numéro ignoré ultérieurement.

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);

Cela produit la requête suivante :

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

Et c'est là que nous gagnons !

WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p1 + @p2