Dapperは「軽量・高速・シンプル」なC#向けマイクロORMです。 EF Coreより圧倒的に速く、SQLをそのまま書けるため、 業務アプリ・デスクトップアプリ・小規模Web APIで特に人気があります。
この記事でわかること
・Dapperの基本(Query/Execute)
・CRUDの実装例(SQLite)
・パラメータとSQLインジェクション対策
・JOIN・複合マッピング(Multi Mapping)
・トランザクション(Transaction)
・非同期(Async)
・Repositoryパターンとの組み合わせ
・EF Coreとの比較
・Dapperの基本(Query/Execute)
・CRUDの実装例(SQLite)
・パラメータとSQLインジェクション対策
・JOIN・複合マッピング(Multi Mapping)
・トランザクション(Transaction)
・非同期(Async)
・Repositoryパターンとの組み合わせ
・EF Coreとの比較
1. Dapperとは?
Dapperは StackOverflow が開発した超軽量ORMで、 「SQLを書く自由」と「高速なマッピング」を両立しています。
■ 特徴
- EF Coreの10〜50倍高速
- SQLをそのまま書ける
- 学習コストがほぼゼロ
- 動的クエリに強い
2. 必要なNuGetパッケージ
Dapper
Microsoft.Data.Sqlite
SQLitePCLRaw.bundle_e_sqlite3
3. モデルクラス
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
4. 基本:SELECT(Query)
using Dapper;
using Microsoft.Data.Sqlite;
var cs = "Data Source=sample.db";
using var con = new SqliteConnection(cs);
var users = con.Query<User>("SELECT Id, Name, Age FROM Users");
foreach (var u in users)
{
Console.WriteLine($"{u.Id}: {u.Name}");
}
5. パラメータ付きSELECT(SQLインジェクション対策)
var user = con.QueryFirstOrDefault<User>(
"SELECT * FROM Users WHERE Id = @id",
new { id = 1 }
);
Dapperは匿名オブジェクトを使うだけで自動的にパラメータ化されます。
6. INSERT(Execute)
var sql = "INSERT INTO Users (Name, Age) VALUES (@name, @age)";
con.Execute(sql, new { name = "Taro", age = 20 });
7. UPDATE
var sql = "UPDATE Users SET Name=@name, Age=@age WHERE Id=@id";
con.Execute(sql, new { id = 1, name = "Jiro", age = 30 });
8. DELETE
con.Execute("DELETE FROM Users WHERE Id=@id", new { id = 1 });
9. トランザクション(Transaction)
using var tran = con.BeginTransaction();
try
{
con.Execute("INSERT INTO Logs (Message) VALUES (@msg)",
new { msg = "Start" }, tran);
con.Execute("UPDATE Users SET Age = Age + 1 WHERE Id = @id",
new { id = 1 }, tran);
tran.Commit();
}
catch
{
tran.Rollback();
throw;
}
10. 非同期(Async)
var users = await con.QueryAsync<User>("SELECT * FROM Users");
UIアプリ(WPF/WinUI)では必須。
11. JOIN(Multi Mapping)
JOIN結果を複数モデルにマッピングできます。
■ User + Order の例
var sql = @"
SELECT u.Id, u.Name, o.Id, o.UserId, o.Amount
FROM Users u
LEFT JOIN Orders o ON u.Id = o.UserId
";
var result = con.Query<User, Order, User>(
sql,
(user, order) =>
{
user.Orders ??= new List<Order>();
if (order != null) user.Orders.Add(order);
return user;
},
splitOn: "Id"
);
12. Repositoryパターンとの組み合わせ
DapperはRepositoryと相性抜群。 SQLをRepositoryに閉じ込めることで、UI層はDBを意識しなくて済みます。
■ IUserRepository
public interface IUserRepository
{
Task<IEnumerable<User>> GetAllAsync();
Task<User?> GetByIdAsync(int id);
Task AddAsync(User user);
Task UpdateAsync(User user);
Task DeleteAsync(int id);
}
■ 実装(Dapper)
public class UserRepository : IUserRepository
{
private readonly SqliteConnection _con;
public UserRepository(SqliteConnection con)
{
_con = con;
}
public Task<IEnumerable<User>> GetAllAsync()
=> _con.QueryAsync<User>("SELECT * FROM Users");
public Task<User?> GetByIdAsync(int id)
=> _con.QueryFirstOrDefaultAsync<User>(
"SELECT * FROM Users WHERE Id=@id", new { id });
public Task AddAsync(User user)
=> _con.ExecuteAsync(
"INSERT INTO Users (Name, Age) VALUES (@Name, @Age)", user);
public Task UpdateAsync(User user)
=> _con.ExecuteAsync(
"UPDATE Users SET Name=@Name, Age=@Age WHERE Id=@Id", user);
public Task DeleteAsync(int id)
=> _con.ExecuteAsync("DELETE FROM Users WHERE Id=@id", new { id });
}
13. EF Coreとの比較(実務視点)
| 項目 | Dapper | EF Core |
|---|---|---|
| 速度 | ◎(非常に速い) | △(遅め) |
| SQL自由度 | ◎(完全自由) | △(LINQ中心) |
| 学習コスト | ◎(ほぼゼロ) | △(やや高い) |
| マイグレーション | ×(自前) | ◎(自動) |
| 大規模開発 | ○(Repository必須) | ◎(Entity中心) |
結論: SQLite × 業務アプリなら、Dapperが最も現実的で高速。
14. 業務アプリ向けベストプラクティス
- SQLはRepositoryに閉じ込める
- トランザクションはUnit of Workで統合
- 非同期(Async)でUIフリーズを防ぐ
- JOINはMulti Mappingでシンプルに
- 大量INSERTはトランザクション+Prepareで高速化
まとめ:Dapperは“軽量・高速・実務向け”の最強ORM
- SQLiteとの相性が抜群
- 高速で、SQLを自由に書ける
- Repository + UoW と組み合わせると長期運用に強い
「EF Coreは重い」「SQLを自由に書きたい」 そんな現場の悩みを解決するのがDapperです。 この記事をベースに、あなたのアプリに最適な高速データアクセス層を構築してみてください。