Skip to content

Simple event-based implementation of DDD aggregate root concept

License

Notifications You must be signed in to change notification settings

VladislavRybnikov/Aggregatable

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🎁 AggregaTable

Main idea of the project is to simplify implementation of entity updates in event based systems. There are situations when multiple microservices work with one entity (or aggregate) and update parts of this entity in different storages, so there should be written non-trivial logic to synchronize data state between this storages.

❗ Unlike other similar projets this does not use same model for aggregation and enetity represantations. Also, data updates performs automaticaly on events in choosen storage From aggregate events to table (no need in separate repositories...)

⚡ Example

Firstly, you should create a class, which will implement AggregateRoot<T>, where T is your existing entity

public class UserAggregateRoot : AggregateRoot<User>
{
...
}

Then there are 2 options how to define event properties to entity properties mappings:

1️⃣ Use interface implementation of IAmUpdateFrom<TMessage>

public class UserAggregateRoot : AggregateRoot<User>,  IAmUpdateFrom<NameUpdate>, IAmUpdateFrom<EmailUpdate>
{

    public IAggregateUpdate Handle(EmailUpdate message) 
        => Update(entity => entity
            .By(e => e.Id, message.Id)
            .Set(e => e.Email, message.Email));

    public IAggregateUpdate Handle(NameUpdate message) 
        => Update(entity => entity
            .By(e => e.Id, message.Id)
            .Set(e => e.Name, message.Name));
}

Where Update is a protected member of AggregateRoot, which is providing Fluent interface for event ➡️ entity mappings

2️⃣ Use protected methods of AggregateRoot inside your ctor

public class UserAggregateRoot : AggregateRoot<User>, 
{
    public UserAggregateRoot() 
    {
        On<PhoneUpdate>(message 
             => Update(entity => entity
                   .By(e => e.Id, message.Id)
                   .Set(e => e.Phone, message.Phone)));

    }
}

Then, you could use your aggregation like following:

var store = new InMemoryStorage();
store.Add("123", new User { Name = "ABC", Email = "abc@mail.com", Id = "123" });

var aggregationContext = new AggregationContext(Assembly.GetExecutingAssembly(), store);
await aggregationContext.SendAsync<User, NameUpdate>(new NameUpdate { Name = "ABCD", Id = "123" });

🏆 What was done

  • ✅ Handling events and updating aggregates in memory
  • ✅ Resolving AggregationRoots from assembly
  • ✅ Mappings registring from interface and ctor (WIP)
  • ✅ Base logic for PostgreSQL mappings, including jsonb (WIP)

➕ TO DO

  • Add Dependency injection
  • Add more integrations with storages and ORMs (sql/nosql, EF, etc...)
  • Add abstractions for automatic event processing
  • Add popular mq integrations (Kafka, Rabbit)

🆘 I will be very grateful for any help with this project (issues, pull-requests, etc...)