導入
「口座Aから引いて、口座Bに足す」——片方だけ成功したら大惨事です。Unit of Work は、複数の変更を1つの単位として溜めておき、最後にまとめて確定(コミット)する設計です。Repositoryと組み合わせて「全部成功か、全部なかったことに」を実現します。
図解
flowchart LR
A["変更1を登録"] --> W["Unit of Work<br/>(変更を溜める)"]
B["変更2を登録"] --> W
W -->|Commit| DB["まとめて確定"]
W -->|Rollback| X["全部破棄"]
style W fill:#e1f5fe
サンプル
var uow = new UnitOfWork();
uow.Register("口座Aから 100 引く");
uow.Register("口座Bに 100 足す");
uow.Commit(); // ここで初めてまとめて反映される
class UnitOfWork
{
private readonly List<string> _pending = new();
public void Register(string change) => _pending.Add(change); // 溜めるだけ
public void Commit()
{
Console.WriteLine($"{_pending.Count} 件の変更を確定");
foreach (var c in _pending) Console.WriteLine($" 適用: {c}");
_pending.Clear();
}
}
出力:
2 件の変更を確定
適用: 口座Aから 100 引く
適用: 口座Bに 100 足す
- Unit of Work は「複数の変更を1単位にまとめて確定」する
- 途中まで溜めておき、
Commitで一括反映(Rollbackで全破棄) - Repositoryと組み合わせ、トランザクション境界を表現する
やってみよう
Commit の代わりに Rollback()(_pending.Clear() だけ)を呼ぶメソッドを足して、溜めた変更が反映されずに消えることを確かめましょう。
演習
// TODO: Register で溜め、Commit で「確定: N件」を出力する Tx を定義してください
___
var tx = new Tx();
tx.Register("a");
tx.Register("b");
tx.Register("c");
tx.Commit(); // 確定: 3件
- 期待される出力:
確定: 3件
ヒント1を見る
class Tx { private readonly List<string> _p = new(); public void Register(string s) => _p.Add(s); public void Commit() => Console.WriteLine($"確定: {_p.Count}件"); }
ヒント2を見る
溜めた件数は _p.Count。$"確定: {_p.Count}件" で出力します
まとめ
- Unit of Work は複数の変更を1単位でコミット/ロールバックする
- 「全部成功か、全部なかったことに」を実現する境界
- Repositoryと組み合わせるのが定番
次回: 画面の関心を3つに分ける MVC です。