Reputation: 13420
I have written an application and tried to use DDD as far as possible. I have run into a problem that I am not sure how to address. Most of the system is driven through users via a web front end, the volume of requests that the application is pretty low and quite CRUDy in nature. However there is one part of the system that integrate into other online systems and the volume of requests will be substantial. We already know from previous experience that we have to streamline this as much as possible.
The scenario is that we want to add create an entity if it doesn't exist but add to the aggregate root if it does exist.
var foo = fooRepo.Get(id);
if (foo != null)
{
foo.Bars.Add(new Bar("hello"));
fooRepo.Add(foo);
}
else
{
var foo = new Foo();
foo.Bars.Add(new Bar("hello"));
fooRepo.Add(fooo);
}
If the action is initiated by a user we don't mind because it is low volume. But the system generated ones it is an extra trip to the DB to determine if it exists. We have already determined that this is a bottle neck for us.
How do I do the above in a DDD way but avoiding the extra trip to the database. I started looking into CQRS because I thought that part of the pattern was to not have repositories so that I could execute commands. But I see that most CQRS examples still use repos and in most examples are still performing get operations for the aggregate roots and then manipulating them and then saving them back.
Clearly repositories don't work in my scenario because I can't treat the problem like an in memory collection of items. (In fact there is just way to much data to even cache everything). Best thing for performance is a straight write to the DB.
Is there anything that can be done in this scenario? Or should I just code an exception?
Upvotes: 3
Views: 66
Reputation: 14064
You could have a FooRepository.AddOrUpdate(foo, bar)
method implemented as a direct INSERT INTO ... IF NOT EXISTS
or MERGE INTO
SQL statement if the extra round-trip is really a concern (which I'm not really sure why it would).
ETL or mass import processes rarely obey the same rules or go through the same layers as UI-based ones. The Application layer will typically be a separate one, and you might even want to bypass the Domain layer in some cases.
It could be a good idea to think about this second input flow in terms of transactions (do these system generated changes come in batches or units, do you want to isolate them the same way you isolate two concurrent end user transactions, etc.?) and create a specific Application layer based on that.
If it turns out that even like this you're too constrained by your aggregate design, you might want to short circuit the domain layer altogether.
Upvotes: 1