I'm trying to use domain driven design while creating a website that is publicly accessible. One problem I'm having is trying to figure out what the aggregate roots should be for my model. I have a pretty good idea of what objects are entity objects and what objects are value objects.
My site, like most public sites, does not allow every user to see every piece of information stored in the site. Instead, they can only see the information they own. In the case of my site users will create "Projects" which they can also share with other users. Yet users can still only see information in projects they created or were invited to join. All the other objects in my model exists within a project and if a project is delete all the objects it contains should also be deleted.
So does this mean that I should have one main "Project" aggregate root type, and one "ProjectRepository" repository? It just seems inefficient to me to load an entire project each time any page on my site is requested. In reality this is not so much of an issue because I'm using NHibernate which will lazy load only the items in the project that are requested. Yet it seems like bad design to have the efficiency of the site depend so heavily on using an ORM with lazy loading.
Here's an update that will hopefully make my question more clear.
First I'm trying to understand if my Project type should be an aggregate root of my model. A Project can exist by itself, whereas the Reports must exist within a Project. If a Project is deleted the corresponding Reports should be deleted. Does this 开发者_如何学运维mean Project could be or should be an aggregate root? This I'm not very clear on.
If Project is an aggregate root then Report should not be correct? As I understand it roots should not be nested in DDD. In addition, only aggregate roots are allowed to be retrieved from repositories. So if Report is not aggregate root then I should not have a ReportsRepository, and instead should only be accessing a Report through a Project retrieved from a ProjectsRepository. So even if a page only requires data from a single report it would need to load the entire Project from the ProjectRepository to get at the report.
In addition, if Project is an aggregate root which contains Reports then removing a Project from a ProjectRepository could also be setup to remove the Reports it contains. Yet if both Project and Report are aggregate roots then wouldn't allowing the ProjectRepository to remove Reports when an Project is removed break the boundaries between aggregates? Aren't aggregate roots and their corresponding repositories suppose to act independent from one another?
I think you are confusing concerns. Security (who can view what) is not a domain concern. Don't let it pollute your domain. If a user cannot view a report within a project, enforce that at someplace other than the domain model.
In addition, I think you might benefit from decoupling your ViewModel (which is used for reading) from your domain model (which is mostly used for writing). They both share a data model (because they're reading from the same DB schema), but they really have different purposes.
In practice (in .NET), decoupling your ViewModel would have most or all of the following characteristics:
- Your ASP.NET MVC views are bound to a single class which represents all the data on the screen. For example, not just the currently selected value in a
<select>
element, but a property representing all the possible<option>
values in the<select>
element.
These are in the MyProject.ViewModel namespace:
public class ProjectLead // Note that this class is specifically designed for display. This is not the domain object.
{
public Guid Id;
public string Name;
}
public class ProjectViewModel
{
public Guid ProjectLeadId;
public IEnumerable<ProjectLead> ProjectLeads;
}
Your Edit()
controller action would call something like:
new ProjectViewModelRepository.Load(id);
ProjectViewModelRepository
will map your data model (nHibernate classes or ADO.NET data rows or whatever) to the ProjectViewModel
instance.
Then, the controller action called by submitting the form in the UI looks like this:
public ActionResult Edit(ProjectViewModel viewModel)
{
var repo = new ProjectRepository();
var project = repo.Load(viewModel.Id);
// Map the properties of the viewmodel to properties/methods of the Project domain class
repo.Save(project);
}
The big idea here is the Single Responsibility Principle. ProjectViewModel
represents how a project is displayed on the screen. The Project
domain class represents the business logic and whatnot associated with a project, independent of how that data is displayed on the screen.
Separating these things really solved a lot of problems due to the fact that I was using my domain classes for multiple purposes: persistence, domain logic, and display. But... if this all sounds like complete overkill I'd verify whether your domain is complicated enough to really warrant DDD.
精彩评论