Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

LINQ to SQL Take ohne Skip verursacht mehrere SQL-Anweisungen

Zuerst - einige Argumente für den Take-Bug.

Wenn Sie einfach nehmen , verwendet der Abfrageübersetzer einfach top. Top10 wird nicht die richtige Antwort geben, wenn die Kardinalität durch den Beitritt zu einer untergeordneten Sammlung gebrochen wird. Der Abfrageübersetzer fügt sich also nicht in die untergeordnete Sammlung ein (stattdessen fragt er erneut nach den untergeordneten Elementen).

Wenn Sie Überspringen und nehmen , dann setzt der Abfrageübersetzer mit einer RowNumber-Logik über den übergeordneten Zeilen ein ... diese Zeilennummern lassen 10 übergeordnete Zeilen zu, selbst wenn dies wirklich 50 Datensätze sind, da jeder übergeordnete Datensatz 5 untergeordnete Elemente hat.

Wenn Sie Überspringen(0) und nehmen , Überspringen wird vom Übersetzer als Nicht-Operation entfernt - es ist, als hätten Sie nie Überspringen gesagt.

Dies wird ein harter konzeptioneller Sprung von dem, wo Sie sind (Aufruf von Skip and Take), zu einer "einfachen Problemumgehung". Was wir tun müssen, ist, die Übersetzung an einem Punkt zu erzwingen, an dem der Übersetzer Skip(0) nicht als Nicht-Operation entfernen kann. Wir müssen Skip anrufen und die übersprungene Nummer zu einem späteren Zeitpunkt angeben.

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

Dies erzeugt die folgende Abfrage:

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

Und hier gewinnen wir!

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