NHibernate and DDD


I bet some of you are screaming for some examples that put all this about NHibernate into the context of DDD. I'd like to end the chapter with exactly that.

Again, I'm not going to use an abstraction layer like NWorkspace here; still, what I describe here could be used for other O/R Mappers as well (and it would be simplified if you do use an abstraction layer).

First, a few words about how to structure the assemblies.

Overview of the Assemblies

Conceptually, I like to think about the repositories as part of the Domain Model, but when no abstraction layer is used on top of the O/R Mapper, I let the repositories live in a separate assembly. That way, I will get the dependencies shown in Figure 9-2.

Figure 9-2. Typical assembly dependencies


Note that the Domain Model doesn't have a dependency to NHibernate now. Still, the Domain Model can use the Repositories if needed. One approach is that the Repositories are implementing interfaces that are in the Domain Model. Then those interface implementations (repositories) are injected in the Domain Model instances at suitable spots.

ISession and Repositories

For all this to work, it assumes that the consumer injects ISession instances to the repositories. That means that the following snippet:

Customer c = (Customer)_session.Load(typeof(Customer), theId);


can be transformed into the following code if a repository takes care of some of the work (not much in this simple case, but some):

Customer c = customerRepository.GetCustomer(theId);


That snippet assumed that the customerRepository was instantiated this way:

//A consumer ICustomerRepository customerRepository =     new CustomerRepository(_session);


So from that point and forward, the repository would have an ISession to use for talking to the backend.

ISession, Repositories, and Transactions

Finally, I prefer to control the start and end of the unit of work in the consumer, outside of the repositories. The following snippet explains what it can look like (with very compact and not recommended transaction code):

//A consumer customerRepository.Add(customer); orderRepository.Add(order); _session.BeginTransaction().Commit();


In that snippet, both repositories are sharing the same ISession.

What Did We Gain?

Let's take a step back. We just took the O/R Mapper for granted and discussed how it could fit in with the concept of repositories.

Think about it the other way around. I mean, we have a repository and now we want to fill it with real code. Assume that you decide to write manual code there. The API for the repository consumer can be the same thing with other implementations, of course, but instead of the following line:

Customer c = (Customer)_session.Load(typeof(Customer), theId);


you would probably have to write quite a lot of code. For example, you need to define the SELECT statement so you get all the columns you need for the customer instance you are about to reconstitute.

Then you need to instantiate the customer instance and shuffle all the values from the resultset row to the instance.

Sure, we can all do that. It's not the complexity that is the problem; it's that this most often is an uninteresting piece of work. And there is a lot more to it. For example, the customer also had a list of ReferencePersons that should be reconstituted at the same time and a whole bunch of other things as well.

When we are done with that code, every single change to the schema or Domain Model will lead to more tedious work for us. Remember, this was a single get operation of a single object.

If we instead use an O/R Mapper, changes are often dealt with by making a few changes to the mapping information and that's it. I believe I'm much more efficient dealing with changes when I don't hand code the uninteresting persistence code.

That thought can be seen in a larger perspective also, because if I know that changes won't be too expensive, I'm much more inclined to do refactorings than in the opposite case!

Let's end this section with a short story from a recent project. I think changes in that project that only affect the pieces (the Domain Model and the database schema) that are dealt with by the O/R Mapper are probably done a magnitude cheaper compared to the changes that affect the persistence code that we have hand tuned! (That said, don't forget that O/R Mappers are of course not the silver bullet either. There are pros and cons.)




Applying Domain-Driven Design and Patterns(c) With Examples in C# and  .NET
Applying Domain-Driven Design and Patterns: With Examples in C# and .NET
ISBN: 0321268202
EAN: 2147483647
Year: 2006
Pages: 179
Authors: Jimmy Nilsson

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net