Entity Framework / Linq to SQL: passer et prendre

Juste curieux de savoir comment Skip & Take est censé fonctionner. J’obtiens les résultats que je souhaite voir du côté client, mais lorsque je connecte le profileur SQL AnjLab et que je regarde le SQL en cours d’exécution, il semble qu’il recherche et renvoie l’intégralité du jeu de lignes au client.

Est-ce que cela retourne vraiment toutes les lignes puis sortinge et réduit les choses avec LINQ du côté client?

J’ai essayé de le faire avec Entity Framework et Linq to SQL; les deux semblent avoir le même comportement.

Je ne suis pas sûr que cela fasse une différence, mais j’utilise C # dans VWD 2010.

Un aperçu?

public IEnumerable ListStores(Func sort, bool desc, int page, int pageSize, out int totalRecords) { var context = new TectonicEntities(); totalRecords = context.Stores.Count(); int skipRows = (page - 1) * pageSize; if (desc) return context.Stores.OrderByDescending(sort).Skip(skipRows).Take(pageSize).ToList(); return context.Stores.OrderBy(sort).Skip(skipRows).Take(pageSize).ToList(); } 

SQL résultant (Remarque: j’exclus la requête Count):

 SELECT [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[LegalName] AS [LegalName], [Extent1].[YearEstablished] AS [YearEstablished], [Extent1].[DiskPath] AS [DiskPath], [Extent1].[URL] AS [URL], [Extent1].[SecureURL] AS [SecureURL], [Extent1].[UseSSL] AS [UseSSL] FROM [dbo].[tec_Stores] AS [Extent1] 

Après quelques recherches supplémentaires, j’ai constaté que les éléments suivants fonctionnaient comme prévu:

 public IEnumerable ListStores(Func sort, bool desc, int page, int pageSize, out int totalRecords) { var context = new TectonicEntities(); totalRecords = context.Stores.Count(); int skipRows = (page - 1) * pageSize; var qry = from s in context.Stores orderby s.Name ascending select s; return qry.Skip(skipRows).Take(pageSize); } 

SQL résultant:

 SELECT TOP (3) [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[LegalName] AS [LegalName], [Extent1].[YearEstablished] AS [YearEstablished], [Extent1].[DiskPath] AS [DiskPath], [Extent1].[URL] AS [URL], [Extent1].[SecureURL] AS [SecureURL], [Extent1].[UseSSL] AS [UseSSL] FROM ( SELECT [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[LegalName] AS [LegalName], [Extent1].[YearEstablished] AS [YearEstablished], [Extent1].[DiskPath] AS [DiskPath], [Extent1].[URL] AS [URL], [Extent1].[SecureURL] AS [SecureURL], [Extent1].[UseSSL] AS [UseSSL], row_number() OVER (ORDER BY [Extent1].[Name] ASC) AS [row_number] FROM [dbo].[tec_Stores] AS [Extent1] ) AS [Extent1] WHERE [Extent1].[row_number] > 3 ORDER BY [Extent1].[Name] ASC 

J’aime beaucoup le fonctionnement de la première option; Passage d’une expression lambda pour le sorting. Est-il possible d’accomplir la même chose dans la syntaxe LINQ to SQL orderby? J’ai essayé d’utiliser qry.OrderBy (sort) .Skip (skipRows) .Take (pageSize), mais cela a fini par me donner les mêmes résultats que mon premier bloc de code. Cela m’amène à croire que mes problèmes sont liés à OrderBy.

====================================

PROBLÈME RÉSOLU

J’ai dû envelopper la fonction lambda entrante dans l’expression:

 Expression<Func> sort 

Ce qui suit fonctionne et accomplit la simplicité que je recherchais:

 public IEnumerable ListStores(Expression> sort, bool desc, int page, int pageSize, out int totalRecords) { List stores = new List(); using (var context = new TectonicEntities()) { totalRecords = context.Stores.Count(); int skipRows = (page - 1) * pageSize; if (desc) stores = context.Stores.OrderByDescending(sort).Skip(skipRows).Take(pageSize).ToList(); else stores = context.Stores.OrderBy(sort).Skip(skipRows).Take(pageSize).ToList(); } return stores; } 

La principale chose qui a résolu ce problème pour moi était de changer le paramètre de sorting Func pour:

 Expression> sort 

Tant que vous ne le faites pas comme queryable.ToList().Skip(5).Take(10) , il ne renverra pas l’ensemble du jeu d’enregistrements.

Prendre

Faire uniquement Take(10).ToList() , fait un SELECT TOP 10 * FROM .

Sauter

Skip fonctionne un peu différemment car il n’y a pas de fonction ‘LIMIT’ dans TSQL. Cependant, il crée une requête SQL basée sur le travail décrit dans cet article de blog ScottGu .

Si l’ensemble du jeu d’enregistrements est retourné, c’est probablement parce que vous faites une ToList() quelque part trop tôt.

Entity Framework 6 solution here …

http://anthonychu.ca/post/entity-framework-parameterize-skip-take-queries-sql/

par exemple

 using System.Data.Entity; .... int skip = 5; int take = 10; myQuery.Skip(() => skip).Take(() => take); 

Essaye ça:

 public IEnumerable ListStores(Func sort, bool desc, int page, int pageSize, out int totalRecords) { var context = new TectonicEntities(); var results = context.Stores; totalRecords = results.Count(); int skipRows = (page - 1) * pageSize; if (desc) results = results.OrderByDescending(sort); return results.Skip(skipRows).Take(pageSize).ToList(); } 

en vérité, ce dernier .ToList () n’est pas vraiment nécessaire car vous retournez IEnumerable …

Il y aura 2 appels à la firebase database, un pour le compte et un pour l’exécution de la liste de diffusion ().

J’ai créé une extension simple:

 public static IEnumerable SelectPage(this IEnumerable list, Func sortFunc, bool isDescending, int index, int length) { List result = null; if (isDescending) result = list.OrderByDescending(sortFunc).Skip(index).Take(length).ToList(); else result = list.OrderBy(sortFunc).Skip(index).Take(length).ToList(); return result; } 

Utilisation simple:

 using (var context = new TransportContext()) { var drivers = (from x in context.Drivers where x.TransportId == trasnportId select x).SelectPage(x => x.Id, false, index, length).ToList(); }