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

Entity Frameworkでenumのビット演算

entity-framework

FlagsAttributeを適用したenum(「ビットフラグ列挙体」と言うんですかね)に対して、Entity Frameworkでビット演算してみました。

ビット演算というよりHasFlagsメソッドを使えるよね?ということを確認した感じです。

エンティティとDBコンテキスト

いつものごとくエンティティとDBコンテキストを作ります。

// フラグ
[Flags]
public enum ItemFlags {
    Apple = 0x01,     // 0000 0001
    Pineapple = 0x02, // 0000 0010
    Pen = 0x04,       // 0000 0100
}

// エンティティ
public class Item {
    public int Id { get; set; }
    // フラグを持つ
    public ItemFlags Flags { get; set; }
}

// DBコンテキスト
public class AppDbContext : DbContext {
    public IDbSet<Item> Items { get; set; }
    // 色々省略
}

データも用意

dbo.Itemテーブルを作ってデータを用意しておきます。

-- こんな感じ
select * from dbo.Item;

/*
Id          Flags
----------- -----------
1           5           -- 0000 0101
2           1           -- 0000 0001
3           6           -- 0000 0110
*/

取得してみる

HasFlagメソッドを使って取得してみます。

// _connectionStringとか色々省略
using (var dbContext = new AppDbContext(_connectionString)) {
    var items = dbContext.Items
        .Where(item => item.Flags.HasFlag(ItemFlags.Pen))
        .ToList();
    foreach (var item in items) {
        Console.WriteLine($"Id = {item.Id}, Flags = {item.Flags}");
    }
}

// 実行結果
/*
Id = 1, Flags = Apple, Pen
Id = 3, Flags = Pineapple, Pen
*/

クエリはこんな感じです。

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Flags] AS [Flags]
    FROM [dbo].[Item] AS [Extent1]
    WHERE (( CAST( [Extent1].[Flags] AS int)) & ( CAST( 4 AS int))) = 4

HasFlagを使わない場合も。

using (var dbContext = new AppDbContext(_connectionString)) {
    var items = dbContext.Items
        .Where(item => (item.Flags & ItemFlags.Pen) == ItemFlags.Pen)
        .ToList();
    foreach (var item in items) {
        Console.WriteLine($"Id = {item.Id}, Flags = {item.Flags}");
    }
}
// 実行結果
/*
Id = 1, Flags = Apple, Pen
Id = 3, Flags = Pineapple, Pen
*/

クエリもこんな感じ。

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Flags] AS [Flags]
    FROM [dbo].[Item] AS [Extent1]
    WHERE 4 = (( CAST( [Extent1].[Flags] AS int)) & (4))