POCO stands for plain old c# objects. It comes from the java equivalent POJO. It's just a hip name to show the world that not everything has to be a derived class. POCOs are not necessarily DTOs, they can be full blown objects with behavior and state and clild POCOs, while DTOs only have state.
Now about your domain - if as you say you are trying to do DDD but your entities don't have behavior than you've been bitten by the anemic domain model anti-pattern. Grab Mr. Evans book on Domain Driven Design and after reading it start planing your model refactoring, preferably with your domain expert.
Also worth mentioning that the anemic domain model is not by itself an anti-pattern, only when you try to do DDD and end up with and anemic model. So if your apps are doing fine and your users are happy, don't bother refactoring for the sake of DDD, just keep it in mind for the future.
This link might help you identify other problems
so it would have been impossible to switch out to another ORM (not
that we wanted to)).
That seems wrong. A major advantage of the repository pattern is that you hide the data access logic and that it is easily exchangeable.
So far it feels as though I put my business logic in my domain model
and via repositories I would work with the ORM (which ever I chose).
However, if I wanted to continue to use the MDA tool for the ORM part
of the application, the model created here would be very anemic (i.e
not contain any business logic). Similarly if I used Entity framework
(.net) or NHibernate for my ORM it too would be an anemic model.? I am
not sure where you would put the business logic if I just used
NHibernate.
An anemic domain model is considered a bad practice by many, for example by Martin Fowler. You should avoid such a design because such a model leads to procedural design techniques rather than a good object oriented design. You then have data classes and manager/processing classes which means you separated state and behaviour. But an object really should be "state and behaviour".
NHibernate does a great job at persistence ignorance. You can hide away the mapping details in XML or with FluentNHibernate and just write plain POCOs. It's very easy to create a rich domain model with NHibernate. I think you can do that with entity framework and the MDA tool, too. As long as this tool produces partial classes you can extend the generated code pretty easily without having to worry that a new generation might destroy your user-written code.
To cut this long story short. When you use NHibernate, nothing, I repeat nothing, stops you from embracing a rich domain model. I recommend using it with FluentNHibernate and mapping by hand. The mapping code takes only 5 to 10 minutes to write. I suppose that the very same is true for entity framework and that its tools at least create partial classes that are easily extensible.
Am I correct in thinking this way, in other words with DDD all the
business logic in the domain and just use the ORM for persistence via
repositories?
For the most part you are correct. You should have a rich domain model. Especially when things become more and more complex, it's easier to maintain and extend when you've designed it properly. But do keep in mind that DDD also knows (Domain Layer and Application Layer) Services to implement business logic and Factories to encapsulate creational logic.
I also tend to differentiate business logic into domain logic and actual application business logic. The domain logic is how the domain interacts and behaves while the application logic, which is a completely different layer, encapsulates how the domain is used for the specific use-case/application. Often times I have to update the domain model to support specific use cases and to make it more powerful.
Best Answer
Repositories and their placement in the code structure is a matter of intense debate in DDD circles. It is also a matter of preference, and often a decision taken based on the specific abilities of your framework and ORM.
The issue is also muddied when you consider other design philosophies like Clean Architecture, which advocate using an abstract repository in the domain layer while providing concrete implementations in the infrastructure layer.
But here's what I have discovered, and what has worked for me, after trying out different permutation/combinations.
To your questions:
I would say there are three distinct layers in DDD applications - the inner domain layer, the outer application layer, and the external world (includes the API/UI).
The domain layer contains aggregates, entities, value objects, domain services, and domain events. These elements are only dependent on each other and actively avoid dependencies any outer layers.
The application layer contains Application Services, Repositories, Message Brokers, and whatever else you need to make your application practically possible. This layer is where most of the persistence, authorization, pub-sub processing, etc. happens. Application Layer depends and knows about the domain layer elements, but follows DDD guidelines when accessing the domain model. For example, it will only invoke methods on Aggregates and Domain Services.
The outermost layer includes API Controllers, serializers, authentication, logging, etc., whatever is not related to business logic or your domain, but very much part of your application.
Repositories lean towards the domain side, meaning they contain methods that are meaningful from a domain point of view (like
GetAdults()
orGetMinors()
). But the concrete implementation can be done in a couple of ways:GetAdults()
instead of.filter(age > 21)
.If you restrict yourself to using repositories only in application services, and control transactions at one place (usually with Unit of Work pattern), Repositories are pretty easy to work with. In my past projects, I have found it extremely useful to restrict all database interaction to repositories instead of sprinkling lifecycle methods in the domain layer.
When I called lifecycle methods (like
save
,update
, etc.) from the aggregate layer, I found it to be extremely complex and difficult to reliably control ACID transactions.