Yes, the deep hierarchy in DDD is beautiful.
Is it good that I get a very extensive unit? - if the reality is so complex and your domain model is better than you can understand, you will have a complex aggregate root.
Yep, Form must be an aggregated root.
all other objects should be value objects - wrong, all other objects should be non-aggregate root objects (with identifier) ββwithout a repository to retrieve them. The Value object has no identifier, and the object of equality of values ββis determined only by its attribute values, and not by equality of identifiers (more details here ).
In this case, the FormRepository will be cluttered with all CRUD methods for child objects - no, the repository should contain only methods related to the aggregated root, i.e. Get<T> , Save<T> where T : IAggregateRoot , once you get an instance of the aggregate root, you can go through the attributes and methods to get what you need. Example:
var formId = 23; var form = _formRepository.Get(formId); var firstGroup = form.Sections.First().Group().First();
or better
var groupIndex = 1; var firstGroup = form.GetGroupAt(groupIndex);
Where
public Group GetGroupAt(int groupIndex) { Sections.First().Group().ElementAt(groupIndex); }
I believe that this view can easily lead to performance problems - if you use CQRS , you will call the Form domain method from the command handler, and if you use NHibernate to save the entity, it will use lazy loading by default and will only load Form from the database, and then load only those objects that you really touch, therefore, for example, Sections.First() will load all sections from the database, but not the groups, but the rest. For queries, you must create a FormDto object (data transfer object) and other, possibly dtos smoothed, to get the data in the required form (which may differ from the structure of your objects, and the user interface can control the structure of dto). Check out the blog for info on DDD / CQRS / NHibernate / Repository