Skip to content

MS_Dapper

nishi_74322014 edited this page Aug 18, 2026 · 1 revision

Dapper

概要

ココで使用したので調査した情報などを纏めました。

Dapper は、Micro-ORM である。

  • Micro-ORM は、RDB とはマッピングしないので、ORM ではない。
  • 言うなれば、DataMapper とか TableMapper と言った機能。
  • 実際、Dapper は、
    • 純粋な実行と Bean(POCO) とのマッピングのみ提供する。
    • パフォーマンスと使いやすさを念頭に置いて開発されている。

補足(実体は拡張メソッド): Dapper は
IDbConnection に対する拡張メソッドの集合であり、
ADO.NETを置き換えるものではなく、その上に薄く乗るものである。

await using var cn = new SqlConnection(cs);
var users = await cn.QueryAsync<User>(
    "SELECT Id, Name FROM Users WHERE DeptId = @deptId",
    new { deptId });

このため、

という性質を持つ。Entity Frameworkとの
最大の違いはこの点にある。

機能

クエリビルダ

  • 基本的には無い。
  • 生 SQL を実行する機能のみ提供される。
  • 以下の拡張ライブラリが該当機能を提供している。

SQL実行

パラメタライズド・クエリ

パラメタライズド・クエリ機能はアリ。

  • ADO.NET よりパラメタライズド処理が書き易い。
  • IN 句に含めるリストに値をバインドする機能などもある。

補足(IN 句の展開): 匿名型のプロパティに配列やリストを渡すと、
Dapper が IN (@p1, @p2, ...) に自動展開する。

var rows = await cn.QueryAsync<User>(
    "SELECT * FROM Users WHERE Id IN @ids",
    new { ids = new[] { 1, 2, 3 } });   // 括弧は書かない

ただし、要素数が変わるたびに別の SQL テキストになるため、
SQL Server のプラン キャッシュが分断される点には注意
SQL Server アドホック クエリ問題の監視)。
件数が多い場合はテーブル値パラメータや一時テーブルを検討する。

トランザクション

トランザクション処理に対応する。

以下のように処理すると良い。

未コミットのものはロールバックになるので、try-catch は不要。

using(var tr = cn.BeginTransaction())
{
    cn.Execute("・・・・", ・・・, tr);
    tr.Commit();
}

補足: Dispose 時に未コミットのトランザクションが
ロールバックされるのは ADO.NET(SqlTransaction)の仕様であり、
Dapper 固有の機能ではない。
なお、cn 自体も usingawait using)で確実に破棄し、
接続プールへ返却すること。

その他

  • ストアド プロシージャを実行可能。

補足: commandType: CommandType.StoredProcedure を指定する。
出力パラメータや戻り値は DynamicParameters で受け取る。

var p = new DynamicParameters();
p.Add("@id", id);
p.Add("@count", dbType: DbType.Int32, direction: ParameterDirection.Output);
await cn.ExecuteAsync("usp_Something", p,
                      commandType: CommandType.StoredProcedure);
int count = p.Get<int>("@count");

ストアド プロシージャ側の詳細はストアド プロシージャを参照。

マッピング

結果セットと Bean(POCO) をマッピングする機能。

  • Query メソッドでは、IEnumerable<dynamic> 型に格納される。
  • Query<T> メソッドでは、T 型の Bean(POCO) にマッピングして、格納される。
  • 列名に別名を付与する場合は、AS 句を使用すれば良い。
  • 大文字・小文字は関係なくマッピングする。
  • 別途マッピング ルールを型毎に設定することが可能。
  • ADO.NET 型付 DataSet の場合よりマッピング処理が書き易い。

移行メモ(誤字): 元ページの IEnumrable<Dynamic>
正しくは IEnumerable<dynamic>

補足(アンダースコア付き列名): USER_NAME のような列名を
UserName プロパティにマッピングしたい場合は、
起動時に以下を 1 度だけ設定する。

Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;

実装

主に、ADO.NET の IDbConnection に拡張メソッドを追加している。

拡張

以下の様な CRUD ヘルパーがある。

更新用の拡張ライブラリ

DapperExtensions

クエリビルダ

Dapper.Rainbow

詳細不明。

Dapper.Contrib

詳細不明。

補足: Dapper.Contrib は Dapper の公式リポジトリに含まれる拡張で、
[Table] / [Key] 属性を付けた POCO に対して
Get<T> / Insert / Update / Delete / GetAll<T> を提供する。
単純な CRUD だけなら SQL を書かずに済むが、
DapperExtensions と同様に主キーが単一であることなどの制約がある。
Dapper.Rainbow は同じく公式リポジトリ内の
テーブル単位のヘルパーだが、現在はほとんど使われていない。

自作の例

以下を参考にすると、上記は微妙らしい。

ココの処理の内容を見ると、

  • ExpressionHelper を引数に取る拡張メソッド
    ≒ LINQ を処理可能な拡張メソッド

で SQL を生成している。

余談:

...と言うことで、
パラメタセットによって、SQL 定義を動的に編集する方法ではなさそう。
Dapper は、パラメタセットは Bean(POCO) のプロパティ ≒ 固定なので、
別の方法で SQL 編集するしか無く、Parameter によって SQL 定義を編集する、
動的パラメタライズド・クエリに組み込むことが不可能だった。

ログ出力

MiniProfiler を使用してログ出力処理を実装できる。

補足(発行 SQL の確認): MiniProfiler の ProfiledDbConnection
接続をラップすると、Dapper 経由の SQL も含めて記録できる。
DB 側から見る場合は
SQLプロファイラ(SQLトレース)
クエリ ストア(SQL Server のログ)を使う。

その他

クラスの階層構造

以下のように ORM できるが、

BA(ビジネス・アプリケーション)ではほぼ、採用しない方式。

  • スキーマ構造に合わせたデータ保持をしない。
    • 論理データ独立性が重要。
    • また、コードが複雑化する。
  • プログラム側での OrderBy で性能が劣化する。

補足(マルチマッピング): Dapper で階層構造を組む場合は、
Query<TFirst, TSecond, TReturn>splitOn を指定する。

var rows = await cn.QueryAsync<Order, Customer, Order>(
    @"SELECT o.*, c.* FROM Orders o
        JOIN Customers c ON c.Id = o.CustomerId",
    (o, c) => { o.Customer = c; return o; },
    splitOn: "Id");

1 対多を組む場合は行が重複して返るため、
アプリ側で GroupBy して畳み込む必要がある。
元ページが指摘しているとおり、この方式は
コードが複雑化しやすく、件数が増えると性能も落ちる。

JSONへの変換

Dapper の Query<dynamic>() の戻り値を JSON へ変換して、
サーバーを JSON 吐く土管にする場合、以下のようにできる。

Oracleでの利用

補足: Dapper は IDbConnection の拡張であるため、
ADO.NETデータプロバイダさえあれば
どの DBMS でも動作する。
ただし、パラメータ記法(SQL Server は @、Oracle は :)や
型のマッピング(Oracle の NUMBER(1)bool など)は
DBMS 依存なので、クロスDB対応の観点では注意が要る。

参考

補足(最新化): Dapper は 2022 年に
Stack Overflow 傘下から DapperLib organization へ移管され、
現在も活発にメンテナンスされている。
ネイティブ AOT や DapperAOT(ソース ジェネレータ版)への対応も進んでいる。

使用例

ADO.NET vs ORM (Entity Framework, Dapper)

ADO.NET vs ORM (Entity Framework, Dapper)


Tags: 移行, データアクセス, .NET開発, ADO.NET

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally