Dapperを使ったデータマッピングのはじめ方

Dapperを使ったデータマッピングのはじめ方

Dapper とは

Dapper は、.NET 環境で使えるシンプルなオブジェクトマッパーです。SQLを実行して取得した結果をオブジェクトに対していい感じにマッピングしてくれます。

ここでは、Dapper の基本的な使い方をまとめます。

Entity Framework との違い

.NET で使える ORM の一つに Entity Framework があります。これはデータベースの情報とオブジェクトを直接マッピングすることで、データベースを意識することなく開発が行えるようになります。

機能的には非常に高性能なのですが、いろいろな面倒事もあったりするので、それが嫌な人は簡単に使える Dapper を検討するとよいでしょう。

Dapper でできることとできないこと

Dapper では、ORM(Entity Framework)ほど高性能なことはできません。以下にできることとできないことを拳げておきます。

できること

  • データのマッピング
  • DB操作のラッピング

Dapper は、IDbConnection というインターフェースを拡張するライブラリです。データのマッピングがいい感じでできるようになります。

できないこと

  • クエリ(SQL)の自動生成
  • マッピングするクラスの自動生成

Dapperはあくまでオブジェクトへのデータマッピングが主な機能なので、SQLを自動で生成することはできません。つまりSQLは自分で書く必要があります。同様にマッピングするクラスを自動的に生成することもできません。

Dapper のインストール

Nuget で提供されているので、利用するプロジェクトに追加しておきます。

[プロジェクト] -> [Nuget パッケージの管理] から Dapper を検索してインストールします。

Dapper によるデータ取得(SELECT)

以下のようなテーブルがあるとします。テーブル名は M_Person です。

このテーブルからデータを取得するようなSQLは以下のようになります。

ADO.NET の場合

まず ADO.NET を使ってデータを取得するパターンを以下に記します。

using (var connection = new SqlConnection())
using(var command = new SqlCommand())
{
    // 接続文字列
    connection.ConnectionString = @"Data Source=[コンピューター名]\SQLEXPRESS1;Initial Catalog=TestDatabase;User Id=sa;Password=sa;";

    // 接続
    connection.Open();

    // コマンド作成
    command.Connection = connection;
    command.CommandText = "SELECT * FROM dbo.M_Person";

    // データリーダーで受け取る
    SqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
        // 処理
        // もしPersonクラスがあって、データをマッピングしたい場合はここに書く
        Console.WriteLine($"ID: {reader["ID"]}  Name: {reader["Name"]}");
    }

    connection.Close();
}

Dapper の場合

上述の通り、Dapper は IDbConnection の拡張メソッドとして基本的な機能を提供します。SqlConnection クラスは IDbConnection を実装しているので、以下のように書くことで簡単にデータの取得・マッピングが可能です。

まず以下のようなマッピングクラスを定義し、取得したデータをこのクラスのオブジェクトにマッピングします。

// マッピング用のクラス
class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
}
// Dapperを追加しておく
// @using Dapper;
using (var connection = new SqlConnection())
using(var command = new SqlCommand())
{
    // 接続文字列
    connection.ConnectionString = @"Data Source=[コンピューター名]\SQLEXPRESS1;Initial Catalog=TestDatabase;User Id=sa;Password=sa;";

    // 接続
    connection.Open();

    // クエリ
    var query = "SELECT * FROM dbo.M_Person";

    // SQLの発行とデータのマッピング
    // 取得データは IEnumerable<Person> 型
    var result = connection.Query<Person>(query);
    foreach (var p in result)
    {
        Console.WriteLine($"ID: {p.ID}  Name: {p.Name}");
    }

    connection.Close();
}

操作は、IDbConnection に対して定義されている拡張メソッド Query<T> で行います。このメソッドは、Select を発行し、取得したデータを 型 のオブジェクトにマッピングしたものを返してくれます。返されるのは IEnumerable<T> 型です。

型引数でマッピングする型を指定しない場合は、dynamic 型で返されます。

// dynamic型で受け取る
dynamic result = connection.Query(query);

dynamic型でも上記コードは同じように動きます。

パラメータで条件を指定する

パラメータの扱いも、Dapperはいい感じに処理してくれます。SQL と Query メソッドの部分を以下のように変更します。

var query = "SELECT * FROM dbo.M_Person WHERE ID = @ID";

// objectのプロパティでパラメータを指定する。
var result = connection.Query<Person>(query, new { ID = 1 });

パラメータは第2引数に渡された object のプロパティを同名のパラメータに自動的にマッピングしてくれます。もちろんSQLインジェクション対策になります。

ここでは匿名クラスを使っていますが、Person クラスでももちろん動作します。

IN句を使った条件に対するパラメータには配列をマッピングできます。

var query = "SELECT * FROM dbo.M_Person WHERE ID IN @ID";

// objectのプロパティでパラメータを指定する。
var result = connection.Query<Person>(query, new { ID = new int[] { 1, 2 } });

Dapper によるデータ更新(INSERT, UPDATE, DELETE)

基本的な扱いはデータの取得と変わりません。

Dapper の場合

実行部分以外はデータ取得の時と同じなの割愛します。

// 実行するSQL
var query = "INSERT INTO M_Person (ID ,Name) VALUES (@ID, @Name)";

// 登録するデータ
var person = new Person() { ID = 10, Name = "伊藤博文" };

// 実行(戻り値は処理結果件数)
var result = connection.Execute(query, person);

ほとんどデータ取得と違うのは Query メソッドではなく、Execute メソッドを使う点です。引数の意味は同じです。

第2引数でパラメータにマッピングされるクラスを指定しています。

データの更新や削除も、SQLが変わるだけであとは同じです。トランザクションを使った例を以下に記します。

using (var connection = new SqlConnection())
{
    // 接続文字列
    connection.ConnectionString = @"Data Source=[コンピューター名]\SQLEXPRESS1;Initial Catalog=TestDatabase;User Id=sa;Password=sa;";

    // 接続
    connection.Open();

    using (var transaction = connection.BeginTransaction())
    {
        try
        {
            // 実行するSQL
            var query = "UPDATE M_Person SET Name = @Name WHERE ID = @ID";

            // 更新するデータ
            var person = new Person() { ID = 3, Name = "井上" };

            // 実行
            var result = connection.Execute(query, person, transaction);

            // コミット
            transaction.Commit();
        }
        catch (Exception)
        {
            // ロールバック
            transaction.Rollback();
            throw;
        }
        finally
        {
            connection.Close();
        }
    }
}

DBのフィールドがスネークケースの場合

マッピングするクラスプロパティがアッパーキャメルケース(例: UserName)、データベースのフィールド名がスネークケース(例: user_name)など、名前が異なる場合はどちらかを合わせないとうまくマッピングしてくれません。

簡単なのはSQL実行時にエイリアスでプロパティの名前に合わせることです。

SELECT user_name AS UserName FROM m_user;

そのほかの機能

SQLの取得結果は単一のクラスだけでなく、複数のクラスに対してもマッピングができる機能もあるようです。そこまで多い分量でもないのでドキュメントに目を通すことをお勧めします。

まとめ

Dapper は、SQLの実行結果を任意の型のオブジェクトにマッピングしてくれます。試しに使ってみましたがお手軽で便利なライブラリだと思います。

基本的には拡張メソッドとして提供されるので、DBアクセスの機能のうち、一部だけを Dapper に置き換えるといったこともできそうです。

以上。

.NET Frameworkカテゴリの最新記事