Published: 02 Nov 2009
By: Andrew Siemer

In this article we will focus on less of the structural issues and instead work on removing our dependency on LINQ to SQL. We will achieve this by employing an object to object mapping tool called AutoMapper.

Contents [hide]

The Stack Overflow Inspired Knowledge Exchange Series

  • TOC Checkout the project homepage of this series to follow our journey from the creation of the famous StackOverFlow website.
  • Introduction

    In the last article took the next step in improving this code by further elevating our logical tiers to physical tiers. This simply meant that we created separate assemblies for each of the separate tiers. By the end of that article we had our web project, a business layer project, domain project, and a data access project. As we saw this alleviated some of the pains that we observed in the previous article. But it surfaced a few other dependencies that we had not really had a good view of until then.

    In this article we will focus on less of the structural issues and instead work on removing our dependency on LINQ to SQL. We will achieve this by employing an object to object mapping tool called AutoMapper. We will create plain old CLR objects (POCO for short) that we can then map our LINQ to SQL objects too. We will then refactor our application to be dependent upon our internal POCO objects instead of the LINQ to SQL generated objects. This will effectively allow our ORM choice to be independent of our code base which will allow us to swap LINQ to SQL out for Entity Framework 4.0 when it comes out next year!

    Discussing our current dependencies

    We have come quite a distance from our simple application. We now have a physically separated architecture in that all of the major concerns are stuffed away in their own separate assemblies. While this is pretty nice we have one major flaw in that the ORM we chose to use, LINQ to SQL, is directly in charge of creating our domain objects for us. This means that any part of our code that works with our core objects has a direct dependency on our data access layer and even worse the specific technology that we use to access our data.

    In order to get rid of this dependency we will have to do a few things. First we will need to relocate our LINQ to SQL .dbml file to the data access project. Then we will create our own POCO classes in the domain project. That is to say that we need to create our own "plain old CLR objects". These will be simple C# classes that have all the fields that we would normally use from the classes that were generated by LINQ to SQL. Then we can create interfaces that define those classes. Using the interfaces we can then map them on top of our LINQ to SQL classes using class partials which will allow us to pass LINQ to SQL objects and our POCO objects interchangeably through our code base. With all of this leg work out of the way we can then use a tool called AutoMapper in our repository layer to map our LINQ to SQL classes to our POCO classes and return a generic set of objects out to our service layer. This should effectively decouple our application from our data access layer and more importantly our dependency on LINQ to SQL.

    Relocating LINQ to SQL

    The first thing to do when relocating files under source control is to work within the source controls tool set. In this case if you are using Ankh SVN then you can cut and paste the .dbml file from the Domain project to the DataAccess file directly. Ankh SVN will then handle deleting the files and moving them to the appropriate place. If you are using Tortoise to move your files around then you need to move the files in Windows Explorer using the Tortoise tools. DO NOT move your files directly in Windows Explorer as that will mess up your source control!

    Once you have relocated your .dbml file build your solution real quick. Any reference to the classes generated by LINQ to SQL will cause errors in the build which will allow you to quickly see what needs more attention. As you get into the code to move things around you will find that in order to get this particular configuration working you will need to add a reference to the DataAccess project from your Web project. While this is generally considered to be a major NO NO we have to do it currently to get things working. We will come back to this down the road once we have removed all the dependencies to our DataAccess layer.

    Creating POCO classes

    Now that we have relocated our .dbml file to the data access project we can now create our plain old CLR classes in our domain project. There are a lot of ways to get this particular task completed. You can manually create a Post class by hand and then create an interface that represents that Post class. Another way to create a POCO class is to generate an interface from the LINQ to SQL class that was generated and then create a POCO class from that interface. I think we all know how to knock up a class so I will demonstrate the second method!

    I am going to show how we can quickly perform this task using a tool called ReSharper (they have a free trial here and it is well worth the money for any C# developer). To get started with our code generation, open up your KE.designer.cs file (the class file that is generated by LINQ to SQL). Then scroll down to the Post class definition. Right click on the Post class and choose Refactor then choose Refactor This...

    That should pop up a window with several options. We are going to choose the extract interface option.

    This will pop up a window with a handful of options.

    Make sure that all of the members that the extract tool finds are of the correct data type. Then click on the All Public button which will check all of the public properties and methods. Next select the "Place in another file" radio button (which will put the interface code into its own file. Then click the next button. This will generate the appropriate interface and place it into an IPost.cs file right next to the KE.dbml file. This is the way wrong place for it so we need to move it to the Domain project. Cut and paste the IPost file into the Domain project. Then open up the IPost interface and remove all the LINQ to SQL generated attributes [Column...].

    Next we need to remove the IPost interface that is inherited by the generated Post class. The reason we have to remove this is that the next time this file is generated the IPost interface will no longer be inherited from. To fix this we need to create a new Post partial class (in the data access project) that will inherit from the IPost interface (from the domain project) which will then be merged into the overall Post class that was generated for us.

    Now that we have an interface and partial Post class we can create our POCO object. To start this we will create a Post class in our domain project. Then we can inherit from the IPost interface. From there we can either choose to implement the Interface (using Visual Studio or ReSharper code generation). With all the code that is generated though you may find it easier to just roll your own class.

    Now that we have gotten this far you can rebuild your solution again. What you will notice now is that your code has mis-matched representations of Post – one in the Domain project and one in the DataAccess project. How do we fix this?

    Introducing AutoMapper

    AutoMapper is a great tool for removing all of the one to one mapping code that we so often see where we have class A on one side and class B on the other side. We point A.Name1 to B.Name1, etc. In this case (and many others which we might get into later) AutoMapper works quite well. It reflects over object A and object B to see what similarities each class has by the name of the properties in both objects as well as the data types of each of those properties. Where AutoMapper finds similarities it will port the data from one side to the other.

    To get things started we need to create an AutoMapperBootstrapper (a class name that I made up) which will handle all of the mappings that we want to configure. In our demonstration we want to be able to map a Post class from the DataAccess project to the Post class from the Domain project. Since we want to make our DataAccess project know how to speak in terms of the Domain objects we will handle all the mapping inside of the DataAccess project. This means that we can pass in Domain.Post objects and handle any mapping that we need to do inside the DataAccess project. And we can pass out Domain.Post objects from the DataAccess project by performing mappings prior to sending out the required classes.

    To do this we need to create an AutoMapperBootStrapper class in the DataAccess project that can be called from some application start up method. In order for this class to work though we need to add a reference to the AutoMapper.dll (now in our dependencies folder – find the dll here). Then we need to define the mapping in both directions – from Domain.Post to DataAccess.Post and from DataAccess.Post to Domain.Post.

    How do I map IEnumerables?

    Having this object to object mapping in place also allows us to account for generic collections of one object to another object. In the case of List<Domain.Post> we can map to List<DataAccess.Post> without adding any additional mapping configurations.

    Listing 1: KnowledgeExchange.DataAccess.AutoMapperBootStrapper.cs

    For this to work though we will need to call into this BootStrapper from our Global.asax file. But since we don't want to call from our web project directly into our data access project we can instead stand up an AutoMapperBootStrapper in our Core project (where we can place other mappings later on).

    Listing 2: KnowledgeExchange.Core.AutoMapperBootStrapper.cs

    With this completed we can then map into our Global.asax file and wire the Core.AutoMapperBootStrapper class.

    Listing 3: KnowledgeExchange.Web.Global.asax

    Reversing our dependencies

    With this entire mapping configuration working as expected we can now move back to our repository class and map between our LINQ to SQL generated Post class and our Domain Post class. This is easily performed by adding a line to the bottom of the PostRepository along with a few minor modifications to the GetAllPosts() method. We need to change the return type from a Post (which is from DataAccess.Post) to Domain.Post. Then instead of returning the result (of type List<DataAccess.Post>) we want to run our List of DataAccess.Post through our Mapper so that we can spit out the List of Domain.Post.

    Listing 4: DataAccess.PostRepository.cs

    Cleaning up

    Now that we have a working mapping in place we can go back to our web project and remove the reference to the DataAccess project. This effectively decouples our presentation layer from our data access layer.

    Analysis

    This small change that we just made may not seem to be that big. But in fact it is! It is a big change that has made our code considerably more flexible in that our code is not dependent on LINQ to SQL. This means that we now fully own our domain layer (LINQ to SQL is not longer generating what we are dependent on). This also means that we can swap in a new data layer (such as Entity Framework) with (perhaps not) a minimum of work but more importantly a minimum amount of impact to our surrounding code. Since our code now only makes calls to our Repository layer and uses our Domain layer then we can swap in a new Repository layer (NHibernate, etc.) with little to no impact on the rest of our code.

    This has gotten us closer to where we want to be. However, this design is still not easily testable nor are the components of the system swappable. While the separation is in place to swap out the repository layer there is still a great deal of work to be done to actually swap in something else.

    Pros

    The pros of this set up are that the majority of our code is decoupled from our data access layer. While it would not be easy to swap in a new repository layer it is technically easy to do.

    Cons

    The down side to this design (of all of the designs that we have looked at) is that the code is still not as flexible as it could be. Nor is it as testable as it could be.

    Comparison Chart

    Table 1: Comparison Chart

    Coding Concepts

    Yes

    Sorta

    No

    Fast/Easy to develop: Can we generate the end product quickly?

    X

    Testable: Can we write tests around the majority of the projects code?

    X

    Flexible for refactoring: Can we easily refactor the code base to add new concepts?

    X

    Well abstracted: Do the users of your code only know what they need too?

    X

    Well encapsulated: Can you change the internals of code without impacting the users of that code?

    X

    Separation of concerns? Is your code well compartmentalized and only doing what it needs to?

    X

    DRY? Does your code follow the "Don't repeat yourself motto?"

    X

    SOLID? Does this code comply with the SOLID principles?

    X

    S: Single Responsibility Principle - there should never be more than one reason for a class to change

    X

    O: Open Closed Principle - should be open for extension but closed for modification

    X

    L: Liskov Substitution Principle - functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it

    X

    I: Interface Segregation Principle - clients should not be forced to depend upon interfaces that they do not use

    X

    D: Dependency Inversion Principle - high level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

    X

    Swappable? Can you swap out an entire layer down the road?

    X

    Distributable? Can you push complex processing of logical areas to a separate server easily to offload computing cycles and scale?

    X

    Summary

    In this article we removed the dependency that our front end and middle tier code had on our data access layer. We now have an application that has no ties to its data access technology. This makes the application more flexible in that the repository can be swapped out for something new but it is no more flexible than it was in our last article.

    In the next article we address the testability issue that our current application has. We will do this by making our application conform to the dependency injection pattern. This will allow us to push up all of our dependencies which makes our code considerably more testable than it currently is.

    <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Andrew Siemer

    I am a 33 year old, ex-Army Ranger, father of 6, geeky software engineer that loves to code, teach, and write. In my spare time (ha!) I like playing with my 6 kids, horses, and various other animals.

    This author has published 29 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
    A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
    Exception Handling and .Net (A practical approach)
    Error Handling has always been crucial for an application in a number of ways. It may affect the exe...
    jQuery Mobile ListView
    In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
    Book Review: SignalR: Real-time Application Development
    A book review of SignalR by Simone.
    JQuery Mobile Widgets Overview
    An overview of widgets in jQuery Mobile.
    Top
     
     
     

    Discussion


    Subject Author Date
    placeholder Great stuff! Maxime Garneau 11/4/2009 3:31 AM
    RE: Great stuff! Andrew Siemer 11/4/2009 6:09 AM
    placeholder Deferred Loading and AutoMapper Tankut Koray 11/16/2009 2:37 PM
    RE: Deferred Loading and AutoMapper Andrew Siemer 11/16/2009 4:10 PM
    placeholder This series is very helpful! Eric Brunswick 11/18/2009 2:32 PM
    RE: This series is very helpful! Andrew Siemer 11/18/2009 5:15 PM

    Please login to rate or to leave a comment.