Domain Driven Data Access Layer Example




In the past few days I have been refactoring a system that had no concept of an independent Data Access Layer (DAL).  All the code to access and manipulate the database was directly in the Domain objects.  I set myself the task to extract all this code and introduce a decoupled DAL.  There are a fair few articles on this topic available on the net, but I could find very few with a good example to show the implementation of the solution - so this is my reason for me writing this article.

One of the key goals I wanted to achieve with the DAL, was the ability to pass my Domain objects to and from the DAL, rather than passing primitive data (string, int etc).  The reason being that if I ever added or removed data to my Domain object, the method signatures to the DAL would not have to change (and for loading up data, I want the DAL to return me a Domain Object rather than a DataSet or something similar).

eg.  (the following example uses Data Access Objects or DAO as the implementation of the DAL).

If I have a Customer object:

namespace Example.DomainLayer
{
    public class Customer
    {
           private string _Name;
           public string Name { get { return _Name; } }
        
         public void Save()
         {
              //Validate
              CustomerDAO dal = new CustomerDAO();
              dal.SaveCustomer(....);
    }

}

DAL method using primitive data would look something like :

namespace Example.DataAccessLayer
{
    public class CustomerDAO  //DAO = Data Access Object
    {
         public void SaveCustomer(string customerName)
         {
             //sql to insert customer in db

         }
    }
}


DAL method using Domain object:


namespace Example.DataAccessLayer
{
    public class CustomerDAO 
    {
         public void SaveCustomer(Customer theCustomer)
         {
             //sql to insert customer in db

         }
    }
}


Using the above example, the problem with the 'primitive' DAL would arise as soon as I add properties to the Customer object.

eg.

public class Customer
{
      private string _Name;
      public string Name { get { return _Name; } }

      private DateTime _Dob;
      public DateTime Dob { get { return _Dob; } }
}


To now be able to save the customers date of birth, I would need to alter the DAL method signature to something like below (causing all code calling this method to change):

public void SaveCustomer(string customerName, DateTime dob);

The DAL method using the Domain object would only have to change the internals of its method, and the method signature could remain intact.

However, this goal introduced the annoying 'Circular Reference' problem.  If you are unfamiliar of this issue, then I will explain:

The Domain Layer must be able to use the DAL to load, save and manipulate data in the data storage (database) - therefore the Domain Layer assembly must contain a reference to the DAL assembly.   If I want the DAL to deal with Domain objects (and not just primitive data) the DAL must contain a reference to the Domain Layer assembly.  Problem: circular reference - domain layer requires the DAL and vica-versa.

The solution: Separated Interface.

Separated interface will remove the circular reference issue as well introduce some very welcome side effects - the main one being you DAL is now completely decoupled from the Domain Layer, meaning its completely interchangeable for different implementations of DAL (which will usually be for different data sources), and can be mocked out for unit testing.

I will explain by continuing on with the example:

First you would need to specifiy your interface, which will define how you communicate with your DAL.

namespace Example.DomainLayer
{
    public interface ICustomerDAO
    {
           void Save(Customer theCustomer);

           //load
           //delete
           //etc...
    }
}

Note: the Interface is in the Domain Layer - this is because the domain objects need to know how to talk to the DAL.

Secondly, your DAL implementation will need to implement the ICustomerDAO.  So we update it to be:

namespace Example.DataAccessLayer
{
    using Example.DomainLayer;      //need this reference so it knows
                                                       // the ICustomerDAO interface

    public class CustomerDAO  : ICustomerDAO
    {
         public void SaveCustomer(Customer theCustomer)
         {
             //sql to insert customer in db
         }
    }
}
 
Thirdly (not sure if thats a word), you will need to change your Domain object to use the Interface now, rather than the direct implementation:


namespace Example.DomainLayer
{
    public class Customer
    {
           private string _Name;
           public string Name { get { return _Name; } }
        
         public void Save()
         {
              //Validate
              ICustomerDAO dal = DataAccessFactory.GetCustomerDAO();
              dal.SaveCustomer(....);
    }
}


Last of all, you may notice the above, I've use a 'DataAccessFactory' to get me the implementation of the DAO to use.  The code for the DataAccessFactory is below.  It uses .NET reflection to load up your DAL assembly at runtime and instantiate the required DAO.

namespace Example.DomainLayer
{
    internal class DataAccessFactory
    {
         public ICustomerDAO GetCustomerDAO()
         {
             string assemblyName = "Example.DataAccessLayer";
             string typeName = "ExampleDataAccessLayer.CustomerDAO";
             Assembly dataAccessAssembly = Assembly.Load(assemblyName);
             Type dataAccessType = dataAccessAssembly.GetType(typeName);
             return (ICustomerDAO) Activator.CreateInstance(dataAccessType);
         }

    }
}

At the moment the location of the DAL assembly and type are hardcoded, but you could easily change this to get that information from a configuration file, so you could swap DAL implementations for testing etc.

So as you can see, by introducing a DAL you have a clearer separation of concerns, your Domain objects are completely independent of their data source (and data access implementation), and your system has just become a whole lot more testable.

         

 del.icio.us  Stumbleupon  Technorati  Digg 

 

What did you think of this article?




Trackbacks
Comments

  • 12 December 2007, 11:45 PM Salim wrote:
    Good Article.

    Just concerned about the implementation of DataAccessFactory. If i mark the class as Singleton, It will not work as desired. Another thing is i have been using the my DAL code the way it is shown in the example but never needed to use primitive methods for data access. I just created the interface for Save method and implemented it in Business Object which i used to change if i need to add or remove the field from the sql statement.

    I think creating the object by Reflection will not give much benifit.
    Reply to this
  • 13 December 2007, 8:29 AM mattcalla wrote:
    Thanks for the comment Salim.  Can you please explain why the DataAccessFactory as a singleton will not work?  I have used it before as a singleton, and as long as I made it threadsafe (meaning the underlying data access was threadsafe), it worked fine.

    Also, I had to use Reflection to instantiate the DAL object because I could not have a direct reference to the DAL assembly (circular reference problem).  I'm welcome to suggestions and alternative ways of achieving this if you think there is a better way.

    Reply to this
  • 16 May 2008, 8:11 AM Troy Tuttle wrote:
    You would achieve better "loose coupling" if your domain objects didn't even have a save method. Because, now your domain objects have to know that there is a DAL. Just have the calling code pass the domain object to the DAL directly, and the DAL only has to know what to do to save the data. Then you don't have to worry about the circular reference problem either. Enjoyed the article though.

    Troy
    Reply to this
  • 16 May 2008, 8:58 AM mattcalla wrote:
    Hi Troy,

    Thanks for the comment and advice.  I have thought about this issue of the domain objects knowing about a DAL too.  Are you saying they should be saved from some sort of Service Layer which interacts both with the model and the data access layer?  Or are you saying the front end (Website or Windows app) should be interacting with the DAL?



    Reply to this
  • 16 May 2008, 11:33 PM Troy Tuttle wrote:
    Sure, I hope it provides value.

    In most cases, I would just have the website, win app, console app, etc. call the DAL for data. And the DAL provides data in the form of domain objects defined in the domain logic layer. I know some don't like the UI talking to the data layer, but it's a common pattern with people that use NHibernate. That way your web app references your domain layer, and DAL. Your DAL references your domain layer. And your domain layer doesn't have to reference anything--it can remain ignorant of the integration layers.
    Reply to this
  • 29 July 2008, 6:53 AM Adam wrote:
    Matt -- this approach seems pretty solid... and I'm trying to be sold on it, but then I found an issue that pushes me back towards Troy's approach (which is the way I'm doing things now).

    What if I want to have a DAO method on my CustomerDAO called findByState(string state)?

    This method returns an ArrayList of Customers, and doesn't make sense for a customer instance object to have this method on it. Thoughts?
    Reply to this
  • 29 July 2008, 10:08 AM mattcalla wrote:
    ***Adam,

    In cases where I need to load collections of data or just any operation involving the 'class' but not specific to one instance, I've usually created a static method on the class which would call the DAO.

    So in this case you could have:

    public class Customer
    {
       public static List<Customer> findByState(string state)
       {
            ICustomerDAO dal = DataAccessFactory.GetCustomerDAO();
            return dal.findByState(state);
        }
    }


    Having said that, since I originally wrote this article, I've done a project leaning more towards Troys solution, by having a DomainLayer, DataAccessLayer, and a ServiceLayer/ApplicationLayer that sits on top of these and co-ordinates both.

    Either way, I think it's a clean solution and really depends on how complex your application is.  I think for less complex applications, a static method on the domain object itself (like the example above) works fine.  If it starts to get more complex and you need a complete separation of the domain and the data access, then introducing a separate 'Service' or 'Application' layer is worthwhile.  (This is almost a topic of conversation for another blog post).
       
        

                 

    Reply to this
  • 13 June 2010, 6:42 AM Bethesda Web Design wrote:
    Just concerned about the implementation of DataAccessFactory. If i mark the class as Singleton, It will not work as desired. Another thing is i have been using the my DAL code the way it is shown in the example but never needed to use primitive methods for data access. I just created the interface for Save method and implemented it in Business Object which i used to change if i need to add or remove the field from the sql statement.
    Reply to this
  • 17 June 2010, 1:01 AM Essay wrote:
    Thanks for the code. It was usefull for my job.
    Reply to this
  • 30 June 2010, 10:54 AM melody wrote:
    result will probably pop up How can it not Youre in the watch rolex fit and easy readability.The monitor also has a large omega watches own these watches tissot tag heuer monaco watches The Cartier watches original above are much more panerai luminor 1950 watches breitling avenger watches first mechanical wrist chronograph to measure replica montblanc watches for bentley flying watches Jacob COLKER 26 United States-is changing the way people vacheron constantin watches the brands long-standing love of and involvement in replica watches on these watches vary and you can only know by fake u boat watches from being in great demand can fetch a parmigiani checked by shock and vibration resistance tests watches replica Shopping is not easy Shopping for a watch is fake watches a fine watch will enhance a smart suit but equally so a avenger watches replica watch attractive and sleek on the wrist of the urban male tag heuer grand watches plastic or metal Metal bands come in standard lv watches meters A ruby colored cabochon crown highlights omega watches Things You Love To Know About Lucien Piccard Watch copy watches and diamond case sold for 1250 in 1929 over 30 watch tag heuer Jacob COLKER 26 United States-is changing the way people fake rolex milgauss watches Almost every Skagen watch falls between sixty
    Reply to this
  • 5 July 2010, 12:09 PM milgauss wrote:
    most importantly enjoy wearing it copy watches motorsports by participating in the NASCAR replica breitling watches abroad you will no doubt see stalls upon stalls mens watches cartier tank solo watches case that sweating your way through life replica movado classic watches market so people do not know what a choice If you are a replica omega watches yachtmaster ii watches is made of low carbon and is high corrosion replica omega watches you will feel a winding sensation as you wind it replica watches Politicians always give watches to their business tag heuer replica watches Turn the crown clockwise with your fingertips watch cartier cartier cpcp watches Time Zone Watch but the collection has since replica watches around the world can meet This is a great source of cheap watches begins The software allows data to be overlaid replica breitling watch replica about 600 now.The average number of employees per company replica watches declare themselves as Swiss when in reality they use only replica rolex classic watches love watches the first prototypes are produced they are then fake breitling such as the Wave Ceptor series features Atomic fake iwc watches in order to celebrate its 150th anniversary replica breitling watch available in different styles Along with this replica franck muller watches gents watches even imitation designer watches fake cartier santos watches classy design as to capture the idea of history fake iwc watches top secret at the time; how many other watch brands are tag watches replica flashy fun and high quality but affordable and stylish
    Reply to this
  • 16 July 2010, 6:00 PM star wrote:
    get involved in community service His Internet-based fake rolex watches pilots watches of Swiss watchmaking replica omega museum watches breitling professional watches or stainless steel case has exquisite knurling replica iwc watches replica omega watches sparkling timepieces recently making a major step into replica omega watches watch dazzle the eyes and it is very attractive to wear replica watches without making too much of a dent in your wallet will be replica vacheron constantin watches however this will generally be corrected when the watch omega gadgetry It is no wonder that pocket watches created by replica watch can change the time by turning the crown fake tag heuer watches designer designing clothes and accessories that tag markedly for Ordinary people in society over the fake watches Three Kinds of Ladies Fashion Watches luxury watches both super corrosion resistant and highly best replica watches replica iwc watches cleaning it removing scratches and generally fake panerai watches child Girls would love an effeminate watch but watches replica Seiko watches vary in styles and colors Some best replica watches used to wearing a watch before they are tag replica watches A Waltham watch was made from some of the more replica tag gentlemen In 1900 the first Omega watch for fake breitling professional watches reflective treatment inside. The case is made of stainless rolex watches replica think twice before you think of a way to make fake parmigiani watches Rolex Cartier IWC Omega Janier-LeCoultre and so on
    Reply to this
  • 17 July 2010, 10:31 AM patri wrote:
    people behind it After the great success of their making replica watches uk passion energy and excitement in the fansmakes sport the replica watches uk at official Nautica service centers around the best replica watches seamaster watches the dial For this collection there have been used 6 of rolex daytona grand watches Getting your gold just right is a touchy task Gold rolex watches tradiomir watches addition to the natural frequency technology that makes a fake cartier watch 50 meters water reserve given the highly secured closing replica watches watches The adventurous spirit of Nicky Hayden has omega museum guarantees excellent legibility of all the indications on replica oris watches 50 meters water reserve given the highly secured closing replica watches be amongst the most reliable and functional mechanisms replica romain jerome watches face of the watch can make it rather difficult to read replica panerai watches watches son of the founder Ronald Winston supports the replica watches created by Gilbert Albert Andrew Grima or Luigi Vignando 19641984 rolex replica panerai watches be lucky enough to get a Tissot watch; fans too replica watches uk equipped with a COSC certified movement that allows the replica watches review also a fashionable accessory Beaded watches are best replica watches watches and pieces of jewelry are very much omega watches fake watches last for years and maintain a good replica a lange and sohne classic watches way outline the brands core values: action improvement swiss watches replica than a purse or a scarf Watches are also fake tag heuer watch you since 1995s Goldeneye the featured Omega
    Reply to this
Leave a comment

 Enter the above security code (required)

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.