Pergunta

Digamos que tenhamos uma entidade raiz agregada de ordem de tipo que relaciona clientes e linhas de pedidos. Quando penso em uma entidade de ordem, é mais natural conceituar -a como não ser definido sem um ID. Um pedido sem um ID parece ser melhor representado como uma solicitação de pedido do que um pedido.

Para adicionar um pedido a um repositório, geralmente vejo pessoas instanciar a ordem sem o ID e depois ter o repositório completar o objeto:

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

O que eu gosto nessa abordagem é que você está adicionando uma instância de pedido a um OrderRepository. Isso faz muito sentido. No entanto, a instância do pedido não possui um ID e, no escopo do consumidor do repositório, ainda não faz sentido para mim que um pedido não tenha um ID. Eu poderia definir uma OrderRequest como uma instância de ordem e acrescentá -la ao repositório, mas isso parece derivar uma maçã de uma laranja e depois adicioná -la a uma lista de laranjas.

Como alternativa, eu também vi essa abordagem:

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

O que eu gosto nessa abordagem é que uma ordem é indefinida sem um ID. O repositório pode criar o registro do banco de dados e reunir todos os campos necessários antes de criar e retornar uma instância de um pedido. O que cheira aqui é o fato de você nunca adicionar uma instância de uma ordem ao repositório.

De qualquer maneira, funciona, então minha pergunta é: tenho que viver com uma dessas duas interpretações ou existe uma prática recomendada para modelar a inserção?

Encontrei esta resposta que é semelhante, mas para objetos de valor:Como devo adicionar um objeto a uma coleção mantida pela raiz agregada. Quando se trata de um objeto de valor, não há confusão, mas minha pergunta diz respeito a uma entidade com a identificação derivada de uma fonte externa (ID de banco de dados gerado automaticamente).

Foi útil?

Solução

Eu gostaria de começar descartando a segunda abordagem. Não apenas parece contra-intuitivo, mas também viola vários bons princípios de design, como Separação de comando-query e a Princípio de menos surpresa.

As opções restantes dependem da lógica do domínio. Se a lógica do domínio determinar que uma ordem sem um ID não tem sentido, o ID é um invariante necessário da ordem, e devemos modelá -lo assim:

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

Observe que, marcando o id campo como readonly Nós o tornamos um invariante. Não há como alterá -lo para uma determinada instância de ordem. Isso se encaixa perfeitamente com Design orientado a domínio's Entidade padronizar.

Você pode aplicar ainda mais a lógica do domínio, colocando uma cláusula de guarda no construtor para impedir que o ID seja negativo ou zero.

Até agora você provavelmente está se perguntando como isso funcionará com IDs gerados automaticamente em um banco de dados. Bem, não.

Não há uma boa maneira de garantir que o ID fornecido ainda não esteja em uso.

Isso deixa você com duas opções:

  • Altere o ID para um GUID. Isso permite que qualquer chamador forneça um ID exclusivo para um novo pedido. No entanto, isso exige que você também use o GUIDS como teclas de banco de dados.
  • Altere a API para que a criação de um novo pedido não aceite um objeto de ordem, mas um OrderRequest, como você sugeriu - o OrderRequest pode ser quase idêntico à classe de ordem, menos o ID.

Em muitos casos, criar um novo pedido é uma operação comercial que precisa de modelagem específica em qualquer caso, por isso não vejo problema em fazer essa distinção. Embora o pedido e o pedido do OrderRequest possam ser semanticamente muito semelhantes, eles nem precisam estar relacionados na hierarquia do tipo.

Eu posso até chegar ao ponto de dizer que eles não deveria estar relacionado, porque o orderrequest é um Objeto de valor enquanto a ordem é um Entidade.

Se essa abordagem for adotada, o método do Addorder deverá retornar uma instância do pedido (ou pelo menos o ID), porque, caso contrário, não podemos conhecer o ID do pedido que acabamos de criar. Isso nos leva de volta à violação do CQS, e é por isso que tendem a Prefir.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top