読者です 読者をやめる 読者になる 読者になる

Entity Framework - SkipメソッドとTakeメソッドを使うとFETCH句とOFFSET句が使われることを確認する

SQL Server 2012からOFFSET句とFETCH句が追加されて、クエリだけでページングを実現できるようになりました。Entity Frameworkを使っているときに、SkipメソッドとTakeメソッドを使うとOFFSET句とFETCH句が使われるの?ってあたりが気になったのでログで発行されるクエリを確認してみました。

以前OFFSET句とFETCH句を試した記事はこちら。

SQL Server - OFFSET 句と FETCH 句 - いちろぐ

以前と同じように1~10までの連番を用意して確認してみます。

テストデータ

with Source(Value) as(
    select 1
    union all
    select Value + 1
    from Source
)
select top 10 *
into Sequence
from Source;

select *
from Sequence;
/*
Value
-----------
1
2
3
4
5
6
7
8
9
10
*/

Entity Frameworkを使ってログを確認

まずモデルとかDbContextとか。ログを出力するようにしています。

[Table("Sequence")]
class Sequence {
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Value { get; set; }
}

class AppDbContext : DbContext {
    public AppDbContext(string nameOrConnectionString)
        : base(nameOrConnectionString) {
        // ログをコンソールに出力
        Database.Log = Console.WriteLine;
    }

    public IDbSet<Sequence> Sequences { get; set; }
}

SkipメソッドとTakeメソッド

SkipメソッドとTakeメソッドを使ってデータを取得してみます。

using (var dbContext = new AppDbContext(connectionString)) {
    dbContext.Sequences
        .OrderBy(entry => entry.Value)
        .Skip(4)
        .Take(3)
        .ToList()
        .ForEach(entry => Console.WriteLine(entry.Value));
    // 5
    // 6
    // 7
}

発行されるSQLはOFFSET句とFETCH句が使われています。

SELECT
    [Extent1].[Value] AS [Value]
    FROM [dbo].[Sequence] AS [Extent1]
    ORDER BY [Extent1].[Value] ASC
    OFFSET 4 ROWS FETCH NEXT 3 ROWS ONLY

Skipメソッドのみ

Skipメソッドだけ使うと、OFFSET句だけが使われています。

using (var dbContext = new AppDbContext(connectionString)) {
    dbContext.Sequences
        .OrderBy(entry => entry.Value)
        .Skip(7)
        .ToList()
        .ForEach(entry => Console.WriteLine(entry.Value));
    // 8
    // 9
    // 10
}
SELECT
    [Extent1].[Value] AS [Value]
    FROM [dbo].[Sequence] AS [Extent1]
    ORDER BY [Extent1].[Value] ASC
    OFFSET 7 ROWS

Takeメソッドのみ

ちなみにTakeメソッドだけ使うと、TOP句になります。

using (var dbContext = new AppDbContext(connectionString)) {
    dbContext.Sequences
        .OrderBy(entry => entry.Value)
        .Take(3)
        .ToList()
        .ForEach(entry => Console.WriteLine(entry.Value));
    // 1
    // 2
    // 3
}
SELECT TOP (3)
    [Extent1].[Value] AS [Value]
    FROM [dbo].[Sequence] AS [Extent1]
    ORDER BY [Extent1].[Value] ASC

さらにちなみにですが、Entity FrameworkではSkipメソッドの前にOrderByメソッドを呼び出す必要があります。呼び出さないとNotSupportedExceptionがスローされます。

The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.

次の環境で確認しました。

  • SQL Server 2012 Developer Edition
  • Entity Framework 6.1.3