I’m implementing a Domain-Driven Design (DDD) architecture and want to leverage strongly typed IDs for my entities. My base AggregateRoot class looks like this:
public abstract class AggregateRoot<TId>
: Entity<TId>
where TId : struct
{
private readonly List<IDomainEvent> _domainEvents = [];
// ...
}
Here’s an example entity:
public readonly record struct AuctionId(Guid Value);
public class Auction
: AggregateRoot<AuctionId>
{
// ...
}
I have a domain event dispatcher interceptor (PublishDomainEventsInterceptor) which I want to work generically with all aggregates:
internal sealed class PublishDomainEventsInterceptor
: SaveChangesInterceptor
{
// ...
public async Task PublishDomainEvents(
DbContext? context)
{
// ...
// Problem: Need a generic way to handle strongly-typed IDs here
var entities = context.ChangeTracker
.Entries<AggregateRoot>() // Issue: Requires type argument
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity);
// ...
}
}
How can I modify my PublishDomainEvents() method or related approach to make it work with AggregateRoot<TId> without knowing the specific TId type in advance? I want to maintain type safety and the benefits of strongly typed IDs.
Thank you in advance for your help, cheers! 🙂
>Solution :
Since your interceptor code does not actually need to use the strongly-typed Id the easiest option would be to introduce a non-generic interface for AggregateRoot<TId> to implement and use it:
public interface IAggregateRoot
{
public IEnumerable<IDomainEvent> DomainEvents { get; }
}
public abstract class AggregateRoot<TId>
: Entity<TId>, IAggregateRoot
where TId : struct
{
// ...
}
And usage:
var entities = context.ChangeTracker
.Entries<IAggregateRoot>()
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity);