質問

顧客と注文明細を関連付ける 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) を持つエンティティに関するものです。

役に立ちましたか?

解決

まず、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 をデータベース キーとしても使用する必要があります。
  • 新しい注文の作成に Order オブジェクトを使用せず、提案したように OrderRequest を使用するように API を変更します。OrderRequest は、ID を除いた Order クラスとほぼ同一にすることができます。

多くの場合、新しい注文の作成は、いずれにしても特定のモデリングを必要とするビジネス操作であるため、この区別を行うことに問題はないと思います。Order と OrderRequest は意味的に非常に似ているかもしれませんが、型階層内で関連している必要さえありません。

彼らはこうまで言うかもしれない いけない OrderRequest は 値オブジェクト 一方、秩序は 実在物.

このアプローチを採用する場合、AddOrder メソッドは Order インスタンス (または少なくとも ID) を返さなければなりません。そうしないと、作成したばかりの注文の ID を知ることができないからです。これにより、CQS 違反に戻ってしまいます。 エンティティ ID の GUID を優先する.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top