Design a No Duplicates Rule in your Domain Model?
Date Published: 16 July 2020
I'm streaming about open source software development most Fridays on Twitch - follow me to get notified when I go online. Recently I was working on building a new API for the [eShopOnWeb reference application and one of the commenters wanted to see how to add validation. Not just simple model validation, but something requiring server-side work: verifying that a product name was unique in the system. I coded up a solution using domain events and Mediatr (in a way I hadn't tried before) and managed to get it working (starting around 1:15). I wrote up the steps to add domain events with mediatr in a separate article, and that generated some discussion as to whether the approach is a good one.
The discussion led me to implement the requirement in a few different ways, all of which you'll find in this GitHub repository, DDD-NoDuplicates. To summarize, the approaches covered are:
- Database UNIQUE / key constraint
- Use a domain service
- Pass necessary data (all existing names) into method on entity
- Pass unique checking service into method on entity
- Pass unique checking function into method on entity
- Pass filtered data (all matching names) into method on entity
- Use an aggregate and put all logic relating to names in it
- Use an aggregate and double dispatch to have logic on entity with aggregate assistance
- Use an aggregate with logic on entity and C# events
- Use an aggregate with MediatR domain events
- Use MediatR domain events on entities without a parent aggregate
Personally, I'm a fan of domain events, so I'd probably go with options 10 or 11 in most cases. This presumes that there's a need to model the rule in the domain layer. In many real world scenarios option 1 makes the most sense, and it's probably the most common approach to this particular problem.
Note: Another option similar to option 8 above would be to have a navigation property on the entity back to its aggregate parent. However, for a variety of reasons I prefer to model navigation relationships one-way, from parent to child, so I haven't covered this option here. Julie Lerman and I cover the thinking behind this in our DDD Fundamentals course.
Do you have another approach? Add an issue or submit a pull request to the repository.
Steve is an experienced software architect and trainer, focusing currently on ASP.NET Core and Domain-Driven Design.