Eコマースのようなアプリケーションを書きたいのですが。
また、類似のアプリケーションでは、製品のプロパティと機能が異なる場合があります。このような機会をシミュレートするために、次のドメインモデルエンティティを作成しました。
Category-これは「エレクトロニクス>コンピューター」、つまり製品のタイプのようなものです。 Сategoriesにはプロパティのリストが含まれています(List <Property>)。
プロパティ-名前、測定単位、データ型を含む独立したエンティティ。たとえば、「名前」、「重量」、「画面サイズ」。同じプロパティに異なる製品を含めることができます。
Product-プロパティに関連する名前と値のリストのみが含まれます。 Valueは、プロパティの値フィールドとフィールドIDのみを含むオブジェクトです。
たとえば、新しい製品を追加するときに、現在のカテゴリ(カテゴリに関連するプロパティを含む)に関連するすべてのデータを知る必要があるため、このスキームでカテゴリを単一集計のようにすることを最初に決定しました。 AddNewProduct(product))。しかし、どのカテゴリにも属さない新しいプロパティを追加する必要がある場合はどうすればよいですか。たとえば、category.AddNewProperty(property)これは、特定のカテゴリにプロパティを追加することを明確に示しているので、実行できません。
次のステップでは、個別のプロパティを個別の集計に決定しましたが、それは単純なエンティティのリストになります。
もちろん、PropertyAggregateのようなものを作成して、プロパティとビジネスルールの内部リストを保持できますが、製品を追加するときに、不変条件をチェックするために、このカテゴリに属するプロパティのリスト全体をカテゴリ内に含める必要があります。しかし、アグリゲート内のリンクを他のアグリゲートに維持することは悪い習慣であることも知っています。
このビジネスケースを設計するためのオプションは何ですか?
DDDパースペクティブでは、Category
、Product
、およびProperty
はエンティティーです。これらはすべて、独自のIDを持つオブジェクトに対応しています。
Category
を単一の集計のルートにしました。一方では、これは理にかなっています。これは、オブジェクトが変更されたときに集約が一貫性を保証するためであり、Product
にはProperties
のCategory
が必要であるためです。
ただし、反対に、単一の集約は、そのすべてのオブジェクトがそれらを所有するルートに関連付けられていることを意味し、すべての外部参照はこの集約ルートを介して行われる必要があります。これは以下を意味します:
Product
は、1つのCategory
にのみ属します。 Category
が削除されると、そのProducts
も削除されます。Property
は、1つのCategory
にのみ属します。別の言い方をすると、「テレビ画面」と「コンピューターモニター」が2つのカテゴリである場合、「テレビ画面:サイズ」と「コンピューターモニター:サイズ」は2つの異なるプロパティになります。2番目の点はあなたの物語に対応していません:「しかし、どのカテゴリにも属さない新しいProperty
を追加する必要がある場合、どうすればいいですか」。また、同じProperties
を異なるCategories
で使用できるかどうかは明確ではありません。
Property
がCategories
とは独立して存在する場合、それは集約の外になければなりません。そして、Properties
をCategories
間で共有したい場合も同じです(高さ、幅、サイズなどに意味があります)。これは間違いなくそうです。
結果は、Property
と集計に属するものとの間のリンクにあります。集計の内部からProperty
に移動できますが、Property
から対応する値に直接移動することはできなくなりました。この navigability 制限は、UML図に表示できます。
このデザインはList<Property>
in Category
、with reference semantic(e.g. Java):リスト内の各参照は、リポジトリ内の共有可能なProperty
オブジェクトを参照します。
この設計の唯一の問題は、Property
を変更または削除できることです。これは集計の外にあるため、集計は不変条件の一貫性を処理できません。しかし、これは問題ではありません。これは、DDDの原則と現実世界の複雑さの結果です。エリックエヴァンスの著書「Domain-Driven Design:Tackling Complexity in the Heart of Software」での引用:
AGGREGATESにまたがるルールは、常に最新であるとは限りません。イベント処理、バッチ処理、またはその他の更新メカニズムにより、他の依存関係を特定の時間内に解決できます。ただし、AGGREGATE内で適用された不変条件は、各トランザクションの完了時に適用されます。
そのため、はい、Property
を変更する場合、サービスがそれを参照するカテゴリをチェックすることを確認して、必要に応じて更新する必要があります。
Product
が単一のCategory
に属しているという仮定が成り立っているのかどうか疑問に思います。
Product
の下に1つのCategories
を提案するオンラインショップをよく見ます。たとえば、「ノートパソコン」カテゴリと「コンピュータ」の下に「ノートパソコンブランドXモデルY」があり、「プリンタ」、「スキャナ」、「ファックス」の下に「多機能プリンタZ」があります。Product
を作成し、後でそれをカテゴリに割り当てて値を入力することはできませんか?集計は単純化されず、集計にまたがるルールがさらに増えます。しかし、あなたのシステムははるかに将来の証明になるでしょう。
私が見ると、これは次の2つの方法のいずれかで解決できます。
つまり、データベース内の特定の製品には、まったく同じテーブル製品を指す外部キーが含まれています。製品は、外部キーがその製品のIDと等しい製品が存在しない場合にのみ製品です。つまり、その下に製品がない場合、それは製品です。
これは少し物事を簡素化します。プロパティと製品の関係は1対多であり、したがって、カテゴリーも製品であるため、カテゴリーも1対多の関係になります。カテゴリにプロパティを追加するのは、プログラムで製品にプロパティを追加するのと同じくらい簡単です。すべてのプロパティをロードすることは、製品のプロパティを関連するカテゴリ製品のプロパティと組み合わせることを意味し、親のないカテゴリ製品に到達するまで続きます。
Eコマースアプリケーションはこの区別をする必要がありますが、とにかくカテゴリの製品をロードする可能性が高い場合でも、カテゴリまたは製品を扱っているかどうかを知ることはパフォーマンスの低下ではありません。また、各製品(カテゴリ)が追加の作業なしでサブ製品のリストを開くため、製品レベルでツリー形式で検索するのにも適しています。
これの欠点は、もちろん、カテゴリに意味をなさない製品に存在する追加情報が、製品に扱いにくい未使用フィールドを作成することです。このソリューションはアプリケーションでより柔軟になりますが、直感的ではありません。
製品はプロパティとの複合的な関係ではなくなりました。 2つをリンクする製品テーブルとプロパティテーブルの両方の外部キーを使用してProductPropertyテーブルを作成します。同様に、プロパティテーブルと多対多の関係を持つカテゴリテーブルと、カテゴリテーブルとプロパティテーブルの両方の外部キーを持つCategoryPropertyテーブルがあります。
製品自体はカテゴリと多対1の関係にあり、基本的に、適切に形式化されたselectステートメントを使用して、製品とカテゴリの両方に関係する固有のプロパティのリストを作成できます。
データベースの観点からは、これは間違いなくよりクリーンで柔軟です。クエリが適切に実行されている場合、アプリケーションは、ほとんどの場合、CategoryPropertyまたはProductPropertyを直接処理せずに実行できます。ただし、カテゴリや製品を所有者として扱うべきではありません。プログラム内の独自のエンティティである必要があります。これはまた、上記のプロパティの管理は、プロパティ自体を作成し、2つの個別のステップでカテゴリまたは製品に関連付けることの問題になることを意味します。確かに最初のソリューションよりも多くの作業が必要ですが、決して難しいことではありません。
これに加えて、そのプロパティのいずれかが他で使用されている場合、カテゴリまたは製品の削除時に追加のチェックを実行する必要があります(特定の製品/カテゴリのすべての関連プロパティを安全に削除できる最初のソリューションとは異なります)。 。
専門的なコンテキストでは、多対多のアプローチを使用して、製品からの距離と距離からのカテゴリに移動します。データが重複する可能性はなく、ある意味では、これら3つそれぞれを独自のエンティティーとして推論する方が簡単です。ただし、より単純なアプリケーションを作成することもできるため、最初のソリューションは決して悪いものではありません。最終的に1つのソリューションから別のソリューションに移行する必要があると思われる場合は、2番目のソリューションを選択することをお勧めします。
幸運を!