Question

Disons que nous avons une entité racine globale de type ordre qui concerne les clients et les lignes de commande. Quand je pense à une entité de commande il est plus naturel de conceptualiser ne pas être défini sans Id. Un ordre sans Id semble être mieux représentée comme une demande de commande d'un ordre.

Pour ajouter une commande à un référentiel, je vois souvent des gens instancier l'ordre sans l'identifiant et alors le dépôt complet de l'objet:

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

Ce que j'aime cette approche est que vous ajoutez une instance de commande à un OrderRepository. Cela a du sens. Cependant, l'instance de l'ordre me ne dispose pas d'un Id, et à la portée du consommateur du dépôt, il fait encore aucun sens que l'ordre n'a pas d'identifiant. Je pourrais définir un OrderRequest être une instance de l'ordre et ajoute que le référentiel, mais qui se sent comme dériver une pomme d'une orange, puis en ajoutant à une liste d'oranges.

Sinon, j'ai vu aussi cette approche:

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
    }
}

Ce que j'aime cette approche est que l'ordre est indéfini sans Id. Le dépôt peut créer l'enregistrement de base de données et de recueillir tous les champs nécessaires avant de créer et retourner une instance d'un ordre. Quelles odeurs ici est le fait que vous ajoutez jamais en fait une instance d'un ordre au dépôt.

De toute façon fonctionne, donc ma question est: Est-ce que je dois vivre avec une de ces deux interprétations, ou est-il une meilleure pratique pour modéliser l'insertion

J'ai trouvé cette réponse qui est similaire, mais pour les objets de valeur: comment dois-je ajouter un objet dans une collection entretenue par racine globale. Quand il vient à un objet de valeur il n'y a pas de confusion, mais ma question concerne une entité identiy dérivée d'une source externe (base de données généré par l'identification automatique).

Était-ce utile?

La solution

Je voudrais commencer par écarter la deuxième approche. Non seulement il ne semble contre-intuitif, il viole également plusieurs bons principes de conception, tels que Commande de requête de séparation et Surprise.

Les autres options dépendent du domaine logique. Si la logique de domaine dicte qu'un ordre sans ID n'a pas de sens, l'ID est un invariant nécessaire de l'ordre, et nous devons modéliser donc:

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;
    }
}

Notez que en marquant le champ id comme readonly nous avons fait un invariant. Il n'y a aucun moyen que nous pouvons changer pour une instance ordre donné. Cela correspond parfaitement à de de Domain-Driven Design Entité .

Vous pouvez encore appliquer la logique de domaine en mettant une clause garde dans le constructeur pour empêcher l'ID d'être négatif ou nul.

Maintenant, vous vous demandez probablement comment cela peut fonctionner avec les ID générés automatiquement à partir d'une base de données. Eh bien, il ne fonctionne pas.

Il n'y a pas une bonne façon de faire en sorte que l'ID fourni n'est pas déjà utilisé.

Cela vous laisse avec deux options:

  • Modifiez l'ID à un Guid. Cela permet à tout appelant de fournir un identifiant unique pour un nouvel ordre. Cependant, cela vous oblige à utiliser Guids les clés de la base de données ainsi.
  • Changer l'API pour que la création d'un nouvel ordre ne prend pas un objet de la commande, mais plutôt un OrderRequest comme vous le suggérez. - la OrderRequest pourrait être presque identique à la classe de la commande, moins l'ID

Dans de nombreux cas, la création d'un nouvel ordre est une opération commerciale qui a besoin d'une modélisation spécifique dans tous les cas, donc je ne vois aucun problème à faire cette distinction. Bien que l'ordre et OrderRequest peuvent être sémantiquement très similaires, ils ne doivent même pas être liés dans la hiérarchie de type.

Je pourrais même aller jusqu'à dire qu'ils ne devrait pas être liés, parce que OrderRequest est un Valeur objet alors que ordre est Entité .

Si cette approche est prise, la méthode AddOrder doit retourner une instance de commande (ou au moins l'ID), car sinon nous ne pouvons pas connaître l'ID de l'ordre que nous venons de créer. Cela nous ramène à la violation CQS qui est la raison pour laquelle j'ai tendance à préfèrent Guids pour les ID d'entité .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top