本文へスキップ
BecomeCoder

C#デザインパターンコース · 第3章 現代の設計パターン · レッスン21

Unit of Work

ブラウザで完結

導入

「口座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 です。

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。