例:
SalesOrder は、SalesOrderHeader と 1 つ以上の SalesOrderItems で構成されます。既存の SalesOrder を編集する場合、SalesOrderHeader を変更でき、SalesOrderItems を追加、変更、および削除できます。すべての変更は、単一のトランザクションで保存する必要があります。複数のユーザーが、オプティミスティック コンカレンシーで同時に SalesOrder を編集できます。
保存を 1 回のトランザクションで行うという要件により、SaleOrderHeader と SalesOrderItems の両方を 1 回のサービス呼び出しで通信することが推奨されると思います。子データをその親と一緒にパッケージ化するということは、子データが追加、変更、または削除されるかどうかについてある程度理解する必要があるということです。
子エンティティの変更追跡は、サーバーまたはクライアントで発生する可能性があります。
サーバーでの変更追跡
この戦略の考え方は、どの SalesOrderItem が追加、変更、または削除されたかを追跡することなく、クライアントが意のままに SalesOrder を変更できるということです。SalesOrderItems の状態は、保存サービスが呼び出されたときにサーバー上で決定されます。
サーバーは、サービス呼び出し間でステートレスのままにする必要があります。これは、SalesOrder を取得してから最終的に保存するまでの間、サーバーが SalesOrder の状態に関する情報を保持できないことを意味します。変更されたオブジェクト グラフをデータベース オブジェクト グラフと比較することによって、サーバーがそのエンティティの状態を判断する場合に残された唯一のオプションです。
nHibernate には、これを実現するためのマージ機能があります。エンティティ フレームワークでは、これを追加する機能リクエストが最も多く投票されました。GraphDiffと呼ばれる EF 用のオープン ソース実装もあります。
サービスの設計と使用が非常に簡単になるため、これは理論的には素晴らしいことのように思えます。ただし、この戦略には 2 つの大きな問題があると思います。1つ目はパフォーマンスです。保存するたびに、オブジェクト グラフ全体を送り返す必要があります。SalesOrderItem が変更されたかどうかにかかわらず、返送する必要があります。そうしないと、サーバーは削除されたと見なします。2 番目の問題はさらに重大で、並行性に関係しています。ユーザー 1 が SalesOrderItem を SalesOrder に追加し、ユーザー 2 が同じ SalesOrder に変更を加えた場合、ユーザー 2 が保存すると、サーバーは、ユーザー 1 によって追加された SalesOrderItem がユーザー 2 のオブジェクト グラフに含まれていなかったため、削除する必要があると想定します。サーバー側の変更追跡の実装でこれを防ぐ方法がわかりません。
クライアントでの変更追跡
もう 1 つの方法は、クライアントにエンティティの変更を追跡させ、保存サービスを呼び出すときにその状態を伝えることです。利点の 1 つは、クライアントが変更されていない子エンティティを送信する必要がないことです。これはパフォーマンスに役立ちます。欠点は、追加、変更、または削除されたかどうかを追跡するために、すべてのエンティティに「ObjectState」の行に沿って何かという名前の追加のプロパティが必要になることです。これにより、サーバー上のエンティティ モデルが非常に煩雑になり、ビジネス ドメインとは関係のない問題でいっぱいになります。これはまた、サービスのさまざまなコンシューマーにこの状態を維持する責任を負わせます。もう 1 つの問題は、削除されたエンティティの処理が困難になることです。SalesOrderHeader は、削除された SalesOrderItems のリストを維持する必要がありますか? または、SalesOrderItems に削除済みの状態を割り当てて、クライアント UI で除外する必要がありますか?
ブリーズJavaScript ライブラリにはクライアント側のエンティティ追跡の独自の実装があることは知っていますが、その実装にはクライアント側とサーバー側の両方のコンポーネントが必要であることが懸念されます。サービスレイヤーは、どちらの側で使用するテクノロジーを分離すべきではないでしょうか? 非 JavaScript クライアントが私のサービスを使用したい場合はどうすればよいですか?
質問
これは、大部分のサービス実装で対処する必要がある一般的なシナリオだと思います。私は何か間違った仮定をしたことがありますか、それとも私は何か異常または普通のことをしていますか? どのような戦略を実行しましたか? 合理的な代替手段はありますか?