Ncqrs: How to raise an Event without having an Aggregate Root

870 views Asked by At

Given I have two Bounded Contexts:

  1. Fleet Mgt - simple CRUD-based supporting sub-domain
  2. Sales - which is my CQRS-based Core Domain

When a CRUD operation occurs in the fleet management, an event reflecting the operation should be published:

  • AircraftCreated
  • AircraftUpdated
  • AircraftDeleted
  • etc.

These events are required a) to update various index tables that are needed in the Sales domain and b) to provide a unified audit log.

Question: Is there an easy way to store and publish these events (to the InProcessEventBus, I'm not using NSB here) without going through an AggregateRoot, which I wouldn't need in a simple CRUD context.

2

There are 2 answers

0
Dennis Traub On BEST ANSWER

According to Pieter, the main contributor of Ncqrs, there is no way to do this out of the box.

In this scenario I don't want to go through the whole ceremony of creating and executing a command, then loading an aggregate root from the event store just to have it emit the event.

The behavior is simple CRUD, implemented using the simplest possible solution, which in this specific case is forms-over-data using Entity Framework. The only thing I need is an event being published once a transaction occurred.

My solution looks like this:

// Abstract base class that provides a Unit Of Work

public abstract class EventPublisherMappedByConvention 
    : AggregateRootMappedByConvention
{
    public void Raise(ISourcedEvent e)
    {
        var context = NcqrsEnvironment.Get<IUnitOfWorkFactory>()
            .CreateUnitOfWork(e.EventIdentifier);
        ApplyEvent(e);
        context.Accept();
    }
}

// Concrete implementation for my specific domain
// Note: The events only reflect the CRUD that's happened.
// The methods themselves can stay empty, state has been persisted through
// other means anyway.

public class FleetManagementEventSource : EventPublisherMappedByConvention
{
    protected void OnAircraftTypeCreated(AircraftTypeCreated e) { }
    protected void OnAircraftTypeUpdated(AircraftTypeUpdated e) { }
    // ...
}

// This can be called from anywhere in my application, once the 
// EF-based transaction has succeeded:

new FleetManagementEventSource().Raise(new AircraftTypeUpdated { ... });
0
Daniel Yokomizo On

If you want to publish the event about something, this something probably is an aggregate root, because it is an externally identified object about a bundle of interest, otherwise why would you want to keep track of them?

Keeping that in mind, you don't need index tables (I understand these are for querying) in the sales BC. You need the GUIDs of the Aircraft and only lookups/joins on the read side.

For auditing I would just add a generic audit event via reflection in the repositories/unit of work.