5

顧客と注文明細を関連付けるOrderタイプの集約ルートエンティティがあるとします。注文エンティティについて考えるとき、IDなしで定義されていないものとして概念化する方が自然です。IDのない注文は、注文よりも注文リクエストとして表現する方が適切なようです。

リポジトリに注文を追加するために、私は通常、IDなしで注文をインスタンス化してから、リポジトリにオブジェクトを完成させるのを目にします。

class OrderRepository
{
    void Add(Order order)
    {
        // Insert order into db and populate Id of new order
    }
}

このアプローチで私が気に入っているのは、OrderインスタンスをOrderRepositoryに追加していることです。それは非常に理にかなっています。ただし、注文インスタンスにはIDがなく、リポジトリのコンシューマーの範囲では、注文にIDがないことは私には意味がありません。OrderRequestをorderのインスタンスとして定義し、それをリポジトリに追加することもできますが、それはオレンジからリンゴを派生させて、それをオレンジのリストに追加するようなものです。

あるいは、私はこのアプローチも見ました:

class OrderRepository
{
    Order AddOrder(Customer customer)
        // It might be better to call this CreateOrder
    {
        // Insert record into db and return a new instance of Order
    }
}

このアプローチで私が気に入っているのは、IDがないと順序が定義されていないことです。リポジトリは、注文のインスタンスを作成して返す前に、データベースレコードを作成し、すべての必須フィールドを収集できます。ここで臭いがするのは、実際に注文のインスタンスをリポジトリに追加することは決してないという事実です。

どちらの方法でも機能するので、私の質問は次のとおりです。これら2つの解釈のいずれかを使用する必要がありますか、それとも挿入をモデル化するためのベストプラクティスがありますか?

私はこの答えが似ていることを発見しましたが、値オブジェクトの場合: 集約ルートによって維持されているコレクションにオブジェクトを追加するにはどうすればよいですか?値オブジェクトに関しては混乱はありませんが、私の質問は、外部ソース(自動生成されたデータベースID)から派生したIDを持つエンティティに関するものです。

4

1 に答える 1

5

まず、2番目のアプローチを除外することから始めたいと思います。直感に反しているように見えるだけでなく、コマンドクエリの分離驚き最小の原則などのいくつかの優れた設計原則にも違反しています。

残りのオプションは、ドメインロジックによって異なります。ドメインロジックがIDのない注文が無意味であると指示する場合、IDは注文の必須の不変条件であり、次のようにモデル化する必要があります。

public class Order
{
    private readonly int id;

    public Order(int id)
    {
        // consider a Guard Clause here if you have constraints on the ID
        this.id = id;
    }
}

フィールドを不変にしたので、idフィールドにマークを付けることに注意してください。readonly特定のOrderインスタンスに対して変更する方法はありません。これは、ドメイン駆動設計エンティティパターンと完全に一致します。

IDが負またはゼロになるのを防ぐために、コンストラクターにGuard句を配置することにより、ドメインロジックをさらに適用できます。

これまでに、データベースから自動生成されたIDでこれがどのように機能するのか疑問に思われるかもしれません。まあ、そうではありません。

指定されたIDがまだ使用されていないことを確認する良い方法はありません。

それには2つの選択肢があります。

  • IDをGUIDに変更します。これにより、すべての発信者が新しい注文に一意のIDを提供できます。ただし、これには、データベースキーとしてもGuidを使用する必要があります。
  • APIを変更して、新しい注文の作成がOrderオブジェクトではなく、提案したようにOrderRequestを取得するようにします。OrderRequestは、IDを除いたOrderクラスとほぼ同じになる可能性があります。

多くの場合、新しい注文を作成することは、どのような場合でも特定のモデリングを必要とする事業運営であるため、この区別をするのに問題はないと思います。OrderとOrderRequestは意味的に非常に似ているかもしれませんが、型階層で関連している必要はありません。

OrderRequestは値オブジェクトであるのに対し、Orderはエンティティであるため、これらを関連付けることはできないと言っても過言ではありません

このアプローチを採用する場合、AddOrderメソッドはOrderインスタンス(または少なくともID)を返す必要があります。そうしないと、作成したばかりの注文のIDがわからないためです。これにより、CQS違反に戻ります。そのため、エンティティIDにはGuidを使用する傾向があります。

于 2010-01-19T20:57:32.877 に答える