DDDによるトランザクションの整合性の確保


9

私はDDDから始めて、国境を越えた一貫性を確保するために集約ルートが使用されることを理解しています。1つのアプリケーションサービスで複数の集計を変更しないでください。

ただし、次のような場合の対処方法を教えてください。

Productsという集約ルートがあります。

グループと呼ばれる集約ルートもあります。

どちらにもIDがあり、個別に編集できます。

複数の製品が同じグループを指すことができます。

製品のグループを変更できるアプリケーションサービスがあります。

ProductService.ChangeProductGroup(string productId, string groupId)

  1. チェックグループが存在する
  2. リポジトリから製品を取得する
  3. グループを設定する
  4. 製品をリポジトリに書き戻す

グループを削除できるアプリケーションサービスもあります。

GroupService.DeleteGroup(string groupId) 1. groupIdが提供されたgroupIdに設定されているリポジトリから製品を取得し、カウントが0または中止であることを確認します2.グループリポジトリからグループを削除します3.変更を保存します

私の質問は、次のシナリオです。

ProductService.ChangeProductGroupで、グループが存在することを確認し(存在する場合)、この確認の直後に、別のユーザーが(他のGroupService.DeleteGroupを介して)productGroupを削除します。この場合、削除されたばかりの製品への参照を設定しますか?

これは、別のドメイン設計を使用する必要がある(必要に応じて追加の要素を追加する)か、トランザクションを使用する必要があるという点で、私の設計の欠陥ですか?

回答:


2

同じ問題があります。

そして、私はこの問題を解決する方法はありませんが、最悪の場合は例外を取得するために、トランザクションまたはDBでの整合性チェックを使用します。

悲観的ロックを使用して、ビジネストランザクションが完了するまで、集約ルートまたはその一部のみをブロックして、ビジネストランザクションがシリアライズ可能なトランザクションとある程度同等になるようにすることもできます。

どのように進むかは、システムとビジネスロジックに大きく依存します。
並行性は決して簡単な作業ではありません。
問題を検出できたとしても、どのように解決しますか?操作をキャンセルするか、ユーザーが変更を「マージ」できるようにしますか?

Entity Frameworkを使用し、EF6はデフォルトでread_commited_snapshotを使用するため、リポジトリから2回連続して読み取ると、データに一貫性がなくなります。ビジネスプロセスがより明確に概説され、情報に基づいた決定を行うことができるようになるときは、そのことを念頭に置いてください。はい、モデルレベルで一貫性をチェックします。これにより、少なくともDBとは別にBLをテストできます。

また、「長い」ビジネストランザクションが発生した場合に備えリポジトリの一貫性について検討することをお勧めします。それが判明したので、それはかなりトリッキーです。


1

これはドメイン駆動設計固有の問題ではなく、リソース管理の問題だと思います。

リソースは、取得時にロックする必要があります。

これは、取得したリソース(このGroup例では集合体)が変更されることをアプリケーションサービスが事前に知っている場合に当てはまります。ドメイン駆動設計では、リソースのロックはリポジトリに属する​​側面です。


いいえ、ロックは「必須」ではありません。実際、実行時間の長いトランザクションを行うのはかなり恐ろしいことです。現代のすべてのORMがそのまま使用できるオプティミスティック並行性を使用するほうがよいでしょう。また、楽観的同時実行性の優れた点は、アトミック更新をサポートしている限り、非トランザクションデータベースでも動作することです。
アーロンノート、2014年

1
実行時間の長いトランザクション内のロックの欠点については同意しますが、@ g18cで説明されているシナリオは、反対のヒント、つまり個々の集計に対する短い操作を示唆しています。
rucamzu 2014年

0

Groupエンティティに製品IDを保存しないのはなぜですか?この方法では、物事を簡単にする単一の集計のみを処理します。

次に、いくつかのタイプの同時実行パターンを実装する必要があります。たとえば、楽観的同時実行を選択した場合は、バージョンプロパティをGroupエンティティに追加し、更新時にバージョンが一致しない場合に例外をスローします。

グループに製品を追加する

  1. 製品が存在するかどうかを確認してください
  2. リポジトリからグループを取得(バージョンIDプロパティを含む)
  3. Group.Add(ProductId)
  4. リポジトリを使用してグループを保存します(新しいバージョンIDで更新し、where句を追加して、バージョンが変更されていないことを確認します。)

多くのORMには、バージョンIDまたはタイムスタンプを使用して組み込まれた楽観的な同時実行性がありますが、独自のものをロールするのは簡単です。これがNhibernate http://ayende.com/blog/3946/nhibernate-mapping-concurrencyでどのように行われるかについての良い投稿です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.