他の2つの答えは一方向です(+1 btw)。元の質問を編集した後に入ってくるので、ここに私の2セントがあります...
値オブジェクトを、他のエンティティ間で共有できる (そして共有されている) 2 つ以上のプロパティを持つオブジェクトとして定義します。それらは単一の集約ルート内でのみ共有できますが、それも問題ありません。それらが共有できる(そして共有されている)という事実だけです。
あなたの例を使用するには、「説明」を値オブジェクトとして定義します。これは、複数のプロパティを持つ「説明」を複数のブックで共有できることを示しています。現実の世界では、それは意味がありません。各本には、その本の著者または出版者のマスターによって書かれた独自の説明があることを私たちは皆知っているからです。へへ。したがって、説明は実際には値オブジェクトではなく、それ自体が Book Aggregate Root Entity 境界内の追加の Entity オブジェクトであると主張します (単一の集約ルートのエンティティ内に複数のエンティティを含めることができます)。再発行された本や新しいリビジョンなどでも、そのわずかな変更を説明するわずかに異なる説明があります。
私はそれがあなたの質問に答えると信じています - 説明エンティティオブジェクトを作成し、メインの Book Entity Aggregate Root (例: Book.GetDescriptions()...) の背後でそれらを保護します。この回答の残りの部分では、この投稿を読んでいる他の人のために、リポジトリで値オブジェクトを処理する方法について説明します...
値オブジェクトをリポジトリに格納し、それらを取得するために、「データベース ファースト」のモデリング アプローチから DDD アプローチに切り替えたときに自分自身と格闘したのと同じ領域に侵入し始めます。私自身、値オブジェクトをDBに保存し、IDなしで取得する方法について、これと格闘しました。一歩下がって、自分が何をしていたかを理解するまで...
ドメイン駆動設計では、データ ストアではなく、ドメイン内の値オブジェクトをモデル化します。それがキーフレーズです。つまり、データ ストアに独立したオブジェクトとして格納されるように値オブジェクトを設計するのではなく、好きなように格納できます。
Address() である値オブジェクトの一般的な DDD の例を見てみましょう。値オブジェクトの定義は、オブジェクトの一意性を作成するために誰のプロパティを合計するかのオブジェクトであるため、DDD は、郵送先住所が完全な値オブジェクトの例であることを示しています。プロパティが変更されると、別の値オブジェクトになります。そして、同じ値オブジェクト (そのプロパティの合計) を他のエンティティ間で共有できます。
郵送先住所は、地球上の特定の場所の経度/緯度である場所です。複数の人が住所に住むことができ、誰かが移動すると、同じ郵送先住所を占有する新しい人が同じ値オブジェクトを使用するようになります。
そのため、住所情報を含む MailingAddress() オブジェクトを持つ Person() オブジェクトがあります。get/update/create メソッド/サービスを使用して、Person() 集計ルートの背後で保護されています。
では、それをどのように保存し、同じ世帯の人々の間で共有するのでしょうか? ああ、そこには DDD があります。DDD から直接データ ストアをモデル化しているわけではありません (それでも、それは素晴らしいことですが)。そうは言っても、Person オブジェクトを表示する単一のテーブルを作成するだけで、その中に郵送先住所の列が含まれます。その情報をデータ ストアから Person() および MailingAddress() オブジェクトに戻して、作成/更新操作中に分割するのは、リポジトリの仕事です。
そうです、データ ストアに重複データが存在することになります。同じ郵送先住所を持つ 3 つの Person() エンティティはすべて、その値オブジェクト データの 3 つの個別のコピーを持っています。これで問題ありません。値オブジェクトは、非常に簡単にコピーおよび破棄できるようになっています。「コピー」は、DDD プレイブックに最適な言葉です。
要約すると、ドメイン ドライブの設計とは、ドメインをモデル化してオブジェクトの実際のビジネス用途を表すことです。Person() エンティティと MailingAddress 値オブジェクトは、アプリケーションで異なる方法で表現されるため、別々にモデル化します。Person テーブルと同じテーブル内の追加の列であるコピーされたデータを永続化します。
上記はすべて厳密な DDD です。ただし、DDD は単なる「提案」であって、従うべきルールではありません。そのため、私や他の多くの人が行ってきた、ゆるい DDD スタイルのようなことを自由に行うことができます。コピーしたデータが気に入らない場合、唯一のオプションは、MailingAddress() 用に別のテーブルを作成し、その上に Identity 列を貼り付けて、MailingAddress() オブジェクトを更新してその ID を持つようにすることです。その ID を、それを共有する他の Person() オブジェクトにリンクするためだけに使用することを知っています (個人的には、クエリの速度を維持するために、3 番目の多対多の関係テーブルが好きです)。その ID (内部修飾子) が集約ルート/ドメインの外部に公開されないようにマスクして、他のレイヤー (アプリケーションや UI など) が MailingAddress の ID 列を認識しないようにします。もし可能なら。また、MailingAddress 専用のリポジトリを作成し、PersonService レイヤーを使用してそれらを正しいオブジェクト Person.MailingAddress() に結合します。
暴言でごめんなさい... :)