iam.Carrot
iam.Carrot

Reputation: 5286

Domain Events with Spring Boot and MongoDB

I am working with DDD and Spring using MongoDB.

Now the since MongoDB is a DocumentDB and no schema validations are present, The AggregateRoot and the Document class that gets stored in the MongoDB are two different classes and the Repository translates content between those two classes while reading and writing data to database.

Since the Root entity class is different from the class being stored to DB, Spring doesn't trigger the DomainEvents of the AggregateRoot.

Upvotes: 3

Views: 1785

Answers (1)

iam.Carrot
iam.Carrot

Reputation: 5286

After a while I figured out the solution, from the upvotes I believe others are facing the same problem, here is the solution:

Question: Can we trigger an explicit invoke for the Domain Events?

Answer: Yes, we can. In SpringBoot we can use/Autowire the ApplicationEventPublisher interface and then call publishEvent(event) method.

If you're making a separate class for Db collection and Aggregate you would need to expose out your DomainEvents and a method for ClearingDomainEvents in your aggregate since the AbstractAggregateRoot<T> has these methods as protected. Below is an example of raising an event on creation:

public class MyAggregateRootClass extends AbstractAggregateRoot<MyAggregateRootClass> 
{
    public MyAggregateRootClass(String property1, String property2) {

        // set the fields here
        registerEvent(new MyAggregateRootCreated(someArgs));
    }

    public Collection<Object> getDomainEvents() {
        return super.domainEvents();
    }

    public void clearDomainEvents() {
        super.clearDomainEvents();
    }
}

The Repository Code would look like:

@Repository
@RequiredArgsConstructor // using lombok here, you can create a constructor if you want
public class MyAggregateRepository {

    private final ApplicationEventPublisher eventPublisher;

    private final AggregateMongoRepository repository;

    public void save(MyAggregateRootClass aggToSave) {

        AggregateDao convertedAgg = new AggregateDao(aggToSave);

        repository.save(convertedAgg);

        // raise all the domain events
        for (Object event : aggToSave.getDomainEvents())
            eventPublisher.publishEvent(event);

        // clear them since all events have been raised
        aggToSave.clearDomainEvents();
    }
}

So does that mean that we generally shouldn't make two different classes, one as AggregateRoot and another the Document Class for storing aggregate roots in mongoDB?

Answer: No, that does not mean that. The goal of the DDD would be to separate infrastructure from the Domain and keep the Domain agnostic of all infrastructure code. If they both are the same then below is the impact:

  • Having the @Document annotation on your Aggregate Class would make you change your Domain if you're switching frameworks or swapping Mongodb with SQL.
  • In the future in case your DB schema needs to change, you would have to either also change your aggregate class or you would have to setup the adapter classes.
  • Since the domain should only change if there is a change in business requirements and not because of infrastructure dependencies, creeping in the infrastructure annotations into the AggregateRoot would not be the best way
So when can you actually just get away with using the same class for Aggregate and Db Collection?

If you do want to just keep it simple and use the same class for both and not create a separate class then make sure you're sure about the below:

  • If you're absolutely sure that you're never going to switch DBs or change frameworks.
  • You have a simple Domain Model and you don't need to store Entities of the Aggregate in a separate collection and you there is no possibility that those Entities would ever grow into their own Aggregates

In the end it depends. Feel free to drop in comments and I'll try my best to answer all of them, quite active on stack.

Upvotes: 1

Related Questions