web-dev-qa-db-ja.com

Entity Framework / Linq to SQL:スキップしてテイク

Skip&Takeがどのように機能するかについて興味があります。私はクライアント側で見たい結果を取得していますが、AnjLab SQL Profilerを接続して実行中のSQLを見ると、行セット全体を照会して返すように見えますクライアント。

実際にすべての行を返し、クライアント側でLINQを使用してソートして絞り込みますか?

Entity FrameworkとLinq to SQLの両方で試してみました。どちらも同じ動作をしているようです。

違いがあるかどうかはわかりませんが、VWD 2010ではC#を使用しています。

洞察はありますか?

public IEnumerable<Store> ListStores(Func<Store, string> 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(注: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]

さらに調査を重ねた結果、次のことが期待どおりに機能することがわかりました。

public IEnumerable<Store> ListStores(Func<Store, string> 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:

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

最初のオプションが機能する方法が本当に気に入っています。ソートのためにラムダ式を渡します。 LINQ to SQL orderby構文で同じことを達成する方法はありますか? qry.OrderBy(sort).Skip(skipRows).Take(pageSize)を使用してみましたが、最終的にコードの最初のブロックと同じ結果が得られました。私の問題は何らかの形でOrderByに結びついていると信じさせられます。

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

問題が解決しました

式で着信ラムダ関数をラップする必要がありました:

Expression<Func<Store,string>> sort
43
Sam

以下は、私が探していたシンプルさを実現し、達成します。

public IEnumerable<Store> ListStores(Expression<Func<Store, string>> sort, bool desc, int page, int pageSize, out int totalRecords)
{
    List<Store> stores = new List<Store>();
    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;
}

私がそれを修正した主なことは、Funcソートパラメータを次のように変更することでした。

Expression<Func<Store, string>> sort
34
Sam

queryable.ToList().Skip(5).Take(10)のようにしない限り、レコードセット全体を返しません。

テイク

Take(10).ToList()のみを実行すると、_SELECT TOP 10 * FROM_が実行されます。

スキップ

TSQLには「LIMIT」関数がないため、スキップは少し異なります。ただし、この ScottGuブログ投稿 で説明されている作業に基づくSQLクエリを作成します。

返されたレコードセット全体が表示される場合は、おそらくどこかでToList()が早すぎているためです。

6
Jan Jongboom

Entity Framework 6ソリューションはこちら...

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

例えば.

using System.Data.Entity;
....

int skip = 5;
int take = 10;

myQuery.Skip(() => skip).Take(() => take);
2
Mick

私は簡単な拡張機能を作成しました:

public static IEnumerable<T> SelectPage<T, T2>(this IEnumerable<T> list, Func<T, T2> sortFunc, bool isDescending, int index, int length)
{
    List<T> 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;
}

簡単な使用:

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();
}
1
Ali Yousefi

これを試して:

public IEnumerable<Store> ListStores(Func<Store, string> 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();
}

実際には、IEnumerableを返すため、最後の.ToList()は実際には必要ありません...

2つのデータベース呼び出しがあります。1つはカウント用で、もう1つはToList()の実行時です。

0
Bryce Fischer