Not Persistence Access?
As you will have
seen by now, and as I said earlier on, the Domain Model  is unaware of
persistence access. Instead, the Service Layer  uses Data Mappers  for
instantiating the Domain Model or for moving the data from the Domain Model
to the database. One early decision I took with this new architecture was
just this, that is, to move the persistence access code out from the Domain
Model itself. I still think it was a good idea, but the main drawback was
that I had to add a way to reach some of the private data of the objects,
as you saw in Listing 8.
As you see, I thought
I was getting a couple of advantages also. Firstly, with this solution I can
instantiate a deep object model with a single roundtrip to the database. For
example, I can instantiate a customer, the orders of that customer and the
items for each order with just a single stored procedure call (that in turn
executes three separate SELECT statements) and a single IDataReader if I think it's a good idea
in certain specific situations. (For most situations Lazy Load  is used
here.) There are solutions to achieve the same thing when having persistence
access inside of the domain objects, but you have to use pretty twisted solutions
for level three and beyond, which I dont think is such a good idea.
purpose of the Lazy Load pattern  is to delay loading objects in an object
graph that you might not need at all or only need later on.
might wonder how I achieve Lazy Load when the domain model isn't supposed
to know about persistence. Thats a very good point. The current solution
I use is to let some of the Service Layer classes implement the IExpander
 interface. Then the Domain Model instance will have an IExpander instance that helps with the
lazy loading. This solution is not only used for expanding a collapsed object,
but also for lazy loading of sub-collections, for example.
I also believe
that portability and testability will increase (I will discuss testability
much more next time), and in a way this solution follows the Single Responsibility
Principle (SRP) .
So far, we have
only discussed very simple cases when all the stored procedure calls were
added to the Unit of Work from a single Data Mapper method. Its just as simple
to call a couple more Data Mapper methods just to add to the very same Unit
of Work instance. No real difference there. The only thing to think about
is that you might have to keep the Unit of Work instance at the instance level
of the Service layer object, as I discussed earlier. And of course, you have
to take care with resultsets so your handler is prepared for what is coming.
What is trickier is if you find that you need several Unit of Works, but have
to work with one single transaction. First of all, this is something I think
you should try to avoid if possible, but there will probably be situations
when you need to have this option. For instance, you might first need to fetch
a value from the database, and depending upon what the value was (and perhaps
some other logic), you should call one or the other stored procedure afterwards.
If/when you get into this situation, you can then easily solve it by adding
an option to somehow read/write the connection and the transaction objects
of the Unit of Work. Don't then forget to take care when implicitly ending
transactions. You should probably skip implicit ending of transactions in
Services transactions are an alternative, but unfortunately declarative
transactions currently also mean distributed transactions. In my opinion
distributed transactions should be used when distributed transactions are
needed, and only then.
If you need to
be able to use several Unit of Work instances within the same Service Layer
method for example, but not within a single transaction, this is also simply
solved. Just do it, so to speak. No extra complexity is added, and as long
as a transaction doesnt have to span several Unit of Work instances, you
dont have to be as careful at all. Just make sure that it is correct that
you dont execute both of the Unit of Work instances within one single transaction.
Remember, the number one goal of transactions is correctness, and nothing
the Persistence Access only for Databases?
No, not at all.
Some data can be found in files, of course, and some via some Web Services,
for example. The Persistence Access can and should hide most of the details,
but we have to think more about how to solve the details. Currently, I think
that we should add more Unit of Work implementations as necessary.
Do you remember
when I talked about letting one database transaction span several Unit of
Work-instances? Perhaps instead of chaining several Unit of Work-instances,
we should use the Command  pattern here, possibly in a way combined with
the Strategy pattern . I havent worked through this yet, but right now
it feels that it will fit nicely into the picture.
purpose of the Command  pattern is to make it possible to bunch together
several commands and execute them one after the other. Its pretty common
that each command knows how to undo itself. The Strategy  pattern is
used when you want to easily switch between different algorithms for a certain
is that the Command pattern comes in as a handy solution for creating a solution
for compensating to simulate transactions for files and Web Services. We can
use this if we dont want to wait for standards and implementations of those
standards for Web Services transactions at least.
Compensating Resource Manager (CRM) of Enterprise Services is another solution
to this problem. Its very appropriate here so I will consider that one
too when I investigate this further.
I will use my blog
 for discussing this article series, among other things. Make sure you
direct your RSS reader to the blog, if you want to follow the development
of the architecture a bit closer than by just reading the articles.
A pure object-oriented domain model by a db-guy. Part 1: Introduction
A pure object-oriented domain model by a db-guy. Part 2: One base class
A pure object-oriented domain model by a db-guy. Part 3: The consumer perspective
A pure object-oriented domain model by a db-guy. Part 4: The Application layer
Martin Fowler; Patterns of Enterprise Application Architecture; Addison-Wesley
2002; ISBN 0‑321‑12742‑0
John Vlissides; Pattern Hatching; Addison-Wesley 1998; ISBN 0-201-43293-5
Jimmy Nilsson; .NET Enterprise Design with Visual Basic .NET and SQL Server
2000; Sams 2001; ISBN 0-672-32233-1
Robert C. Martin; Agile Software Development. Principles, Patterns and Practices;
Prentice Hall 2002; ISBN 0-13-597444-5
Erich Gamma et al; Design Patterns; Addison-Wesley 1994; ISBN 0-201-63361-2
Jimmy Nilssons weblog; http://www.jnsk.se/weblog/