views:

109

answers:

2

What do you do if you need to generate a read-only list of data on a page and that data would naturally come from several, potentially 5 or more different repositories?

We're using DDD and have been forcing access to our database through repositories, but there is a scenario that has come up that doesn't seem to fit DDD and we're trying to decide on the best pattern to use.

For example, let's say that you have a community based web site with videos, forums, blogs, etc. You've got a forums page with a list of comments. This is rough, but I hope it makes sense.

<table>
<tr><td>User Name (with possible link)</td><td>User's community score.</td><td>User Avatar</td><td>User's E-mail</td><td>User's blog</td><td>User's videos</td></tr>
</table>
<table>
<tr><td>This is a comment.</td></tr>
</table>

So each comment contains several different pieces: a user Name, a community score, an avatar, an e-mail, a user's blog and a user's video page. Traditionally, these pieces of information would all come from separate repositories.

The issue with that is efficiency. Repositories can be maximized, but only around the aggregate for which their created. Using repositories becomes inefficient for read access the moment that you need access to data that lies in more than one repository.

My solution is to create a UserInformation DTO with the relevant information and place a method in the UserForumsRepository with the signature

ILIst<UserInformation> GetUserForumsUserInformationByForumPostID(int forumPostID).

One of my colleagues suggests that using a DTO in this way breaks the design pattern that we've been using and suggests that a better way would be to get a list of forum comment ids and then pass those ids into the various repositories to return the results.

My own view is that main purpose of repositories is to encapsulate business logic which is important for the CUD parts of CRUD, but that read-only lists should be generated in the way that makes most sense. If appropriate, I think that it even makes sense to remove the read-only list methods from the repository entirely (e.g. such as in a common widget that's used across multiple different types pages).

How do you handle this situation?

A: 

I hate answering my own question, but I haven't had any comments and I appear to have found the answer from the usual suspect: Fowler.

In our design, which is the same as most simple DDD, our application is connecting to our repositories directly to obtain and update data. However, in more complex scenarios, there is an additional service layer between the concrete repositories and the application layer. Instead of passing objects from the domain model to the client, you pass DTOs.

According to Fower (PoEAA 401), you ". . . can't usually transfer objects from the domain model, . . . because the objects are usually connected in a complex web that's difficult, if not impossible, to serialize." Fowler continues "Instead you have to transfer a simplified form of the data from the domain objects."

So actually, especially in a distributed system, passing DTOs to the client is the norm. How the service layer assembles those DTOs from the domain layer should be of no interest to the client.

I must admit that I'm a little distressed by this statement by Fowler. I very much like the convenience of using the domain model in ASP.Net MVC. It makes it especially convenient when creating master-detail UI design pattern views. When a strongly typed view is associated with a customer, it only takes a line of code to include a CustomerOrders.ascx partial view(with type IList) and passing in customer.Orders to the partial view. Maybe it's ok to continue to do this, so long as the domain object is behaviorless, but that's a future question.

John
A behavior less domain model is an anti patten called an anemic domain model. We use dto's to solve the problem you are having. One or more repositories are combined to map multiple entities to one flattened dto that is then sent to the client. If you send your entities to the client, you rub the risk of your domain model having it's state mutated in an inconsistent way.
Sean Chambers
Are you doing this in a service layer or in the repository layer?
John
A: 

Answer #2

What's needed here is an extra service layer between the concrete repository and the client. Sometimes, what the client needs is different from what the repository layer provides, especially in the case where the repositories may be distributed. A service layer allows you to define coarsely grained methods and hide the finely grained details from the client. With a services layer, you're then passing lightweight DTOs on to the client, instead of full fledged business objects.

To map the business objects to DTOs and the reverse, the tool Automapper is becoming quite popular.

John