よろしい、ならばMicro-ORMだ
きよくら ならみ
第二回 中国地方DB勉強会
2013/10/05
自己紹介
• きよくら ならみ
– @kiyokura / id:kiyokura
• 岡山生まれ岡山育ちのプログラマー
– 現在は県内の某製造業で社内SE
• NET系の開発やWebアプリ開発
– Microsoft MVP for ASP.NET/IIS
ORMとSQLと
ORM派 vs SQL派(?)
• よく論争になってる(?)
• でも今日はそんな話はしません
• (そもそも個人的には対立軸ではないと思って
ます)
先に私の個人的結論を言うと
• ORM使えばいい
• むしろどんどん使うべき
ただし銀の弾丸じゃない
• コンテキスト次第
– 「デメリットが勝つ」というべきか、
「メリットが有効に働かない」というべきか
– そういうことはある
でも面倒なのは避けたいです
• ORMが使えなくても
– なるべくならば
今日のお話の流れ
• ORMについて
• ORMがあんまり有効でないケース
• Micro-ORMについて
ORMとは
ORMの代表的な機能
• クエリの自動生成
• データ(値)のマッピング
• DB操作のラッピング
• ソースコード自動生成
• もちろん実装によっては無い機能もある
"面倒くさい"ところを便利に
• SQL
• エンティティになるクラス
• DB操作をいちいち書かなくていい
• 単体テストが必要な個所が削れる
• 実装によって異なる場合があります
便利なのでどんどん使えばいいよ
• そう思います
ORMが有効じゃないケースとは
ORMが有効でないケースもある
• 往々にして"銀の弾丸"は無いです
• 幾つかあると思いますが、もっとも根本
的なお話をしたいと思います
DB設計がORMに適さないケース
• 例えばデータが単一のアプリケーション
内に閉じないケース
こんな感じとか
販売データ
労務データ
製造データ
研究開発
データ
顧客データ
販売管理システム 生産管理システム
賞与計算システム 製造品質管理
システム
データベース ">" アプリケーション
• 何が「>」?
– 利用範囲や権限、寿命等
• データが横断的に利用される
– 例えば基幹系システムでは良くありますよね
• キーワード:
データ中心アプローチ(DOA)
その他ORMが使いにくいと思われるケース
• DB設計がイケてない!
– パフォーマンスが出ない
– 適切にリレーションが貼られていない
– もちろん私にそれを変更する権限は(
• ドライバ・プロバイダが使いたいORMに
対応してない
– たまにある
ORMが使えないならどうするか
• もちろん、使わずに書くしかない
• SQL組み立てて...
• DBの接続情報を読み込んで...
• DBに接続して...
• おっと、例外時の処理もしっかりしとか
ないと
• パラメータをバインドして…
• クエリを実行!
そして…
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット、
• レコードの値を変数にセット
決まりきったことは書きたくない
• 生産効率云々...
• Lazinessはプログラマの三大美徳の一つ
• どうにかズル出来ないものか
真面目な話、
• 自力でコードを書く量が少ないに越した
ことはない
– 仮に実装にかかる時間が同じとしても
– バグを積み込む可能性は減る
• テストするべき個所が減る
そこで、今日の本題です
Micro-ORMってなに??
大体こんなもの
• 軽量で
• 高速な
• プチORM…とでも言うもの
"プチ”故に...
クエリの
自動生成
データ
(値)の
マッピング
DB操作の
ラッピング
ソース
コード自
動生成
☆物によってはある程度するものも
このあたりを面倒見てくれる
• DB操作のラッピング
– クエリ実行は面倒見てくれる
– 接続やトランザクション制御は
"ある程度"は自動でやってくれる
• 値のマッピング
– クエリの結果セットの取得とマッピング
– クエリのパラメータへのマッピング
軽量で早い
• ソースコード1~2ファイルとかの実装が
多い
• あんまり複雑なことしない分早い
• クエリの実行速度は
"あなたが組んだSQLに依存する"
Micro-ORMの実装例の紹介
実装例
• 代表的な実装例
– dappar dot net
– Massive
– PetaPoco
• あれ?なんか.NETの実装ばっかりだ:p
• dapper dot netを例に少しだけ紹介
おことわり
• .NETの実装ですのでコードも.NETです
• 今日はざっくりとさらっと
• 詳しいコード例やデモ、他のORMとの比
較などは…
来週(10/12)のヒーロー島で!
• 「ヒーロー島 秋の収穫祭 2013」
• こちらでは、よりコード例や機能の紹介など
を行いたいと思います
• 10/12(日)、八丁堀のMS中四国支店
– 八丁堀電停から徒歩3分
• 詳細とお申し込みはこちら
– http://heroshima.jp/EventInfo/autumn2013
dapper dot net
• .NET向けのMicro-ORM
– Dapper.NETとも書かれる
• オープンソース
– ApachとMITのデュアルライセンス
• サイトはこの辺
– https://code.google.com/p/dapper-dot-net/
– https://github.com/SamSaffron/dapper-dot-
net
dapper dot net
• 対象データベース
– たいがい行ける気がします
• ADO.NETに準拠したプロバイダがあれば
• SQL Server / Oracle / MySQL / PostgreSQL
• 最悪ODBCあれば行ける気がする
導入は簡単
• NuGetで一発インストール
実際の使用例
• 実際にdapperを使った例をお見せします
...とその前に
• dapperやORMを使わずに書いた
DBアクセスの例
public IList<EmployeeEntity> FindAll()
{
using (var cn = new SqlCeConnection(connectionString))
{
cn.Open();
var sql = "select ID, Name , Age , Email From Employee;"
var cmd = new SqlCeCommand(sql , cn);
var result = new List<EmployeeEntity>();
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
{
result.Add(new EmployeeEntity()
{
ID = (int)dr["ID"],
Name = (string)dr["Name"],
Age = (int)dr["Age"],
Email = (string)dr["Email"]
});
}
}
return result;
}
}
var cmd = new SqlCeCommand(sql , cn);
var result = new List<EmployeeEntity>();
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
{
result.Add(new EmployeeEntity()
{
ID = (int)dr["ID"],
Name = (string)dr["Name"],
Age = (int)dr["Age"],
Email = (string)dr["Email"]
});
}
}
①実行の下準備(コマンドオブジェクト作成)
②実行して
③型変換とかしながらクエリの結果をオブジェクトにマッピング
カ
ラ
ム
が
増
え
る
と
も
っ
と
面
倒
に
!
dapperを使うとどうなるか
public IList<EmployeeEntity> FindAll()
{
using (var cn = new SqlCeConnection(connectionString))
{
cn.Open();
var sql = "select ID, Name , Age , Email From Employee;"
return cn.Query<EmployeeEntity>(sql).ToList();
}
}
return cn.Query<EmployeeEntity>(sql).ToList();
この一行で、実行結果のマッピングまですべて完了!
ポイントはQuery拡張メソッド
• コネクションオブジェクトの拡張メソッ
ドとして実装
• Query拡張メソッドの各種オーバーロード
デモ
もう一つ、例
• パラメータをバインドしてみます
こちらも非dapperから
public EmployeeEntity FindByID(int id)
{
using (var cn = new SqlCeConnection(connectionString))
{
cn.Open();
var sql = "select ID, Name , Age , Email From Employee where ID = @ID;"
var cmd = new SqlCeCommand(sql, cn);
var param = cmd.CreateParameter();
param.ParameterName = "ID";
param.SqlDbType = System.Data.SqlDbType.Int;
param.Direction = System.Data.ParameterDirection.Input;
param.Value = id;
cmd.Parameters.Add(param);
var result = new List<EmployeeEntity>();
using (var dr = cmd.ExecuteReader())
{
if (dr.Read())
{
return new EmployeeEntity()
{
ID = (int)dr["ID"],
Name = (string)dr["Name"],
Age = (int)dr["Age"],
Email = (string)dr["Email"]
};
}
else
{
return null;
}
}
}
}
var sql =
"select ID, Name , Age , Email From Employee where ID = @ID;"
var cmd = new SqlCeCommand(sql, cn);
var param = cmd.CreateParameter();
param.ParameterName = "ID";
param.SqlDbType = System.Data.SqlDbType.Int;
param.Direction = System.Data.ParameterDirection.Input;
param.Value = id;
cmd.Parameters.Add(param);
①Parameterオブジェクトを作成して
②Parameterオブジェクトに値その他を設定
③Commandオブジェクトにパラメータをセット
パラメータの数だけ、
これをやらないといけない!!!
これがdapperだと…
public EmployeeEntity FindByID(int id)
{
using (var cn = new SqlCeConnection(connectionString))
{
cn.Open();
var sql = "select ID, Name , Age , Email From Employee where ID = @ID;"
return cn.Query<EmployeeEntity>( sql , new { ID = id }).SingleOrDefault();
}
}
return cn.Query<EmployeeEntity>( sql ,
new { ID = id })
.SingleOrDefault();
Queryメソッドの第二引数に、
パラメータと名前の一致するプロパティを持ったオ
ブジェクトを渡してやるだけ
(匿名クラスでもOK)
パラメータが増えたら…
new {
ID = id,
Name = "ほげほげ",
Age = 17
}
もっといろいろな機能があります
• 詳細は公式のGithub等にあるサンプルを
見てみてください
– 私もblogで書こうとしてるけど下書きだけ溜
まっててまだ公開出来てません...
想定FAQ:1
• Q:実績あるの?
• A:結構いろいろあるらしい
– IT技術者的には「Stack Overflowで使われて
いる」といえば納得できるかな?
– そもそも作者がStack Overflowの中の人
– Stack Overflowのパフォーマンス改善のため
に作られたらしい
想定FAQ:2
• Q:実際、パフォーマンスどうなの?
• A:相当早いよ
– 詳しくは公式サイトにベンチマークあるので
参照
想定FAQ:3
• Q:PHPで普通に書くのと一緒じゃね?
• A:静的型付けなのに同じってすごくね?
– コンパイラの恩恵
– IDEのサポート
• インテリセンス
• リアルタイムにコンパイルエラー
まとめ
ORMは便利な道具
• 有効に使えるところではどんどん使おう
• でも使えないケースもある
– 設計思想やスケールのアンマッチ
– 銀の弾丸は無い
Micro-ORMという選択肢
• 軽量高速、省力プログラミング
• ORMとSQLのいいところどりも可能
ご清聴ありがとうございました
and , Question?

よろしい、ならばMicro-ORMだ