Sweets Junkie

もぅマヂ無理。ムズかしぃコト。。。ぉぼぇてらんなぃから。。。ブログかコ。。。デザィンみづらくてぇ。。。それどころじゃなぃ。。。

【C#】Dapperについてまとめてみた

C#で使える軽量なORマッパー「Dapper」についてのナレッジが貯まってきたのでまとめてみます。

#1 Dapperとは

C#で書かれた軽量なORマッパー。
ただし、クエリ生成やソース自動生成などの機能は備えていない。
その代り高速。ORマッパーを嫌う人は速度面を指摘するけど、気になることはないと思う。

とにかく多機能なORマッパーを使いたい人はEntityFramework使ってどうぞ。


#2 導入方法

NuGetから「Dapper」検索GO!!


#3 使い方

①単一テーブルをSelectしてみる。
対象のテーブルは以下。

テーブル名:Users
カラム:UserName、Age

Dapperを使用してDBの取得結果をオブジェクトにマップするにはマップ先となるクラスを用意する必要がある。
基本的にはカラム名=変数名とする。大文字小文字は区別しない。
カラム名=変数名とならない場合はマッピングできないので、クエリ側でAS句を使い変数名と合わせる必要がある。
今回は以下のようなクラスを用意。

class User
{
     public String UserName { get; set; }
     public int Age { get; set; }
}

では早速Usersテーブルの情報をUserクラスにマッピング

public User GetUser()
{
   // DBコネクションを取得(ここは適当
  Connection con = ConnectionUtil.GetConnection("接続文字列");
 
  // DBに投げるクエリ @UserName はパラメータ
  String sql = @"SELECT * FROM Users WHERE UserName = @UserName";
  // クエリを実行して、取得結果をUserクラスにマッピング
  // パラメータは dynamic型で指定
  // SingleOrDefault() を使うと、複数件取得できた場合に例外、0件取得の場合にNullを返してくれる。
  // Single() を使うと、複数件取得、0件取得の場合に例外を発射する。
  return con.Query<User>(sql, new { UserName = "三木眞一郎" }).SingleOrDefault();
}

以上。これだけでマッピングされる。シンプルで超素敵。
ソースの説明はコメントを参照されたし。

②複数レコード取得してみる。
対象テーブルは①と同じ。

 public List<User> GetAllUser()
{
  // DBコネクションを取得(ここは適当
  Connection con = ConnectionUtil.GetConnection("接続文字列");
 
  // DBに投げるクエリ
  String sql = @"SELECT * FROM Users";
  // クエリを実行して、取得結果をUserクラスにマッピング
  // List<User>にキャストする
  return List<User> con.Query<User>(sql);
}

以上。キャストするだけでListにもマッピングできる。

③1対1の関係のテーブルをJOINして取得してみる。
対象のテーブルは以下。

テーブル名:Users
カラム:UserName、Age、JobId

テーブル名:Jobs
カラム:JobId、JobName

Jobsテーブルのマップ先としてUserクラスにJobクラスを定義する。

class User
{
     public String UserName { get; set; }
     public int Age { get; set; }
     public int JobId { get; set; }
     public Job Job { get; set; }
}
 
class Job
{
     public int JobId { get; set; }
     Public String JobName { get; set; }
}

UsersテーブルとJobsテーブルを結合してUsersクラスにマッピングしてみる。

public User GetUserAndJob()
{
  // DBコネクションを取得(ここは適当
  Connection con = ConnectionUtil.GetConnection("接続文字列");
 
  // DBに投げるクエリ @UserName はパラメータ
  String sql = @"SELECT * FROM Users u INNER JOIN Jobs j ON u.JobId = j.JobId WHERE UserName = @UserName";
  // クエリを実行して、取得結果をUserクラスにマッピング
  // Query<User, Jobs, User> は、<1つ目のテーブルのクラス、2つ目のテーブルのクラス、returnするクラス>
  // パラメータは dynamic型で指定
  // splitOnには2つ目のテーブルの開始位置のカラム名を指定
  // SingleOrDefault() を使うと、複数件取得できた場合に例外、0件取得の場合にNullを返してくれる。
  // Single() を使うと、複数件取得、0件取得の場合に例外を発射する。
  return con.Query<User, Jobs, User>(
     sql, 
     (user, job) => { user.Job = job; return user }, 
     new { UserName = "三木眞一郎" },
     splitOn: "JobId").SingleOrDefault();
}

以上。これも簡単。
ちなみに3つ以上のテーブルを結合する場合は、「con.Query」に3つ目のテーブルを追加して、splitOnにはカンマ区切りで区切り位置のカラム名を指定すればよい。

④ストアドプロシージャをよんでみる。
「sp_getUsers」というストアドプロシージャがあるとして。

public List<User> GetAllUser()
{
  // DBコネクションを取得(ここは適当
  Connection con = ConnectionUtil.GetConnection("接続文字列");
 
  // DBに投げるクエリ
  String procedure = "sp_getUsers";
  // クエリを実行して、取得結果をUserクラスにマッピング
  // CommandTypeにストアドプロシージャを指定
  // List<User>にキャストする
  return List<User> con.Query<User>(procedure, commandType: CommandType.StoredProcedure);
}

以上。CommandTypeを指定する以外は①~③と一緒。

ものすごいざっとまとめたけど、これで事足りるくらいDapperはシンプルなライブラリです。
ORマッパーなのにクエリの自動生成は無いの?と思うかもしれないけど、世の中にはクエリ自動生成にアレルギーのある人とか、ストアドプロシージャー教の人も多いので、個人的にはこれくらいの機能で丁度よく感じています。
特に私の会社ではストアドプロシージャでまみれているのでとても役に立ちました。ありがとうDapper!!