Wednesday, February 18, 2009

Using the Repository Pattern with CSLA.NET, Part 2

In my last post, we built an abstraction for a data access layer used by CSLA.NET business objects based on the Repository Pattern.  We started by creating two base interfaces, IRepository<TContext> and IContext and then used them to define a set interfaces that abstracted the data access for a simple order entry system.  Those interfaces were:
  • IOrderRepository - represented the repository for orders and line items; a factory object that can create the other repository objects
  • IOrderContext - the context that the IOrderRepository creates that performs the actual data access
  • IOrderInfoDto - a DTO for order summary entities
  • IOrderDto - a DTO for orders
  • ILineItemDto - a DTO for order line items
We then demonstrated how objects based on those interfaces would be called from the data access areas within actual CSLA.NET business objects (in the DataPortal_* methods).  We also showed how the repository object was injected in via dependency injection.  In our case, we used the Unity IOC Container but any IOC Container or dependency injection framework would do.
In this post we're going to build a concrete implementation of our abstract data access layer.  In other words, we'll build classes that implement the above interfaces.  In this case, we'll use LINQ to SQL as our actual data access technology.  However, given the high level of abstraction of our repository pattern implementation, we could conceivable build concrete implementations in many other technologies such as LINQ to Entities, <insert your favorite ORM here>, or even plain old ADO.NET.

LINQ to SQL Classes

Before we jump into the implementation of our interfaces, we need to first build our LINQ to SQL classes.  These classes will play an integral role in our concrete implementation.
LINQ to SQL requires that a physical database exist, so assume that we've started with a simple SQL Server database that contains an Orders table and a LineItem table with a one-to-many relationship between them.  We can then add an Orders.dbml file (LINQ to SQL Classes item) to a Visual Studio 2008 project and drag both tables onto the design surface:
Orders-dbml-screenshot
Visual Studio (actually LINQ to SQL) does a lot of work behind the scenes when we do this.  It code generates a LINQ to SQL DataContext class called OrdersDataContext and two entity classes called Order and LineItem that map to the database tables.
You may also notice is the screen shot above that we've added a set of stored procedures to our database that perform all the inserts, updates, and deletes, and they show up as methods on the OrdersDataContext class.  While LINQ to SQL entity classes have the ability to perform these operations on their own, they have a limitation that forces us to use a alternative mechanism, like stored procedures, instead.  We'll investigate this issue further a little later on in the post.
At this point, the OrdersDataContext, Order, and LineItem classes could be used by a set of CSLA.NET business objects to perform all the required data access.  However, the business objects would be be tightly coupled to the LINQ to SQL code and therefore there would be no easy way to abstract the LINQ to SQL code so it could be mocked for unit testing purposes.  Let's see how we can migrate this code into a concrete implementation of our repository pattern abstraction.

Concrete DTO's

Before we jump into the concrete repository and context objects, let's take a quick look at how we implement the DTO's.  LINQ to SQL makes this relatively easy since the entity classes code generated by LINQ to SQL are the DTO's.  All we need to do is make them implement our DTO interfaces.  Since the LINQ to SQL code generation is done using partial classes, this is quite easy.
First the, concrete IOrderDto class:
partial class Order
    : IOrderDto
{

    byte[] IOrderDto.Timestamp
    {
        get
        {
            return this.Timestamp.ToArray();
        }
        set
        {
            this.Timestamp = new Binary(value);
        }
    }

    IEnumerable<ILineItemDto> IOrderDto.LineItems
    {
        get
        {
            return this.LineItems.Cast<ILineItemDto>();
        }
    }

}
At a minimum, we need to define the partial class Order (which binds to the code-generated Order class at compile time) that implements the IOrderDto interface.  But we also need to add a couple explicit IOrderDto property implementations.
The first is due to the fact that the Order class that was code-generated by LINQ to SQL has a Timestamp property that is of the LINQ to SQL-specific type Binary.  However, the IOrderDto interface defines the Timestamp property as a byte array, which is not specific to a data access technology.  Therefore we need to add the IOrderDto.Timestamp property explicitly and marshal the Binary and byte array values back and forth.
The second explicit property implementation is IOrderDto.LineItems.  The Order class code-generated by LINQ to SQL also defines a LineItems property, but it's of type EntitySet<LineItem>.  Therefore, we need to convert between the two and a handy way to do it is to use the Cast extension method.
The concrete ILineItemDto class is very similar, but we only have to add an explicit implementation of its the ILineItemDto.Property:
partial class LineItem
    : ILineItemDto
{

    byte[] ILineItemDto.Timestamp
    {
        get
        {
            return this.Timestamp.ToArray();
        }
        set
        {
            this.Timestamp = new Binary(value);
        }
    }

}
Now, with the concrete DTO's defined, let's move onto the concrete repository and context classes.

Concrete Order Repository

You may recall the role of the repository object is to be a factory for all of the other objects needed by the data access layer.  It's main job is to create the associated context.  Therefore our order repository will need to create an order context.  It will also need to be able to create any DTO's required by data access methods that require DTO's as inputs. 
Given that, here's our concrete OrderRepository class:
public sealed class OrderRepository
    : IOrderRepository
{

    IOrderContext IRepository<IOrderContext>.CreateContext(bool isTransactional)
    {
        return new OrderContext(isTransactional);
    }

    IOrderDto IOrderRepository.CreateOrderDto()
    {
        return new Order();
    }

    ILineItemDto IOrderRepository.CreateLineItemDto()
    {
        return new LineItem();
    }

}
A fairly simple implementation of a factory.  The CreateContext method creates a new instance of our concrete OrderContext (which we'll see its implementation just ahead), passing a value to its constructor, telling it whether or not it needs to be transactional.  Then we have two methods for creating DTO's: CreateOrderDto and CreateLineItemDto.  Notice that what we're actually returning are instances of the two entity classes code generated by LINQ to SQL since they implement the required DTO interfaces.

Concrete Order Context

While the repository object is the factory that creates all the data access objects, the context object plays the star role in actually performing the data access operations.  Therefore, the OrderContext class is going to have the most meat of any of our concrete repository pattern classes.  Let's examine the OrderContext class in chunks since there's a lot going on. 

Basic Implementation of OrderContext

First, let's take a look at the class definition itself and its constructor that we know takes a isTransactional boolean parameter:
public sealed class OrderContext
    : IOrderContext
{

    private OrdersDataContext _db;
    private TransactionScope _ts;

    public OrderContext(bool isTransactional)
    {
        _db = new OrdersDataContext();
        if (isTransactional)
            _ts = new TransactionScope();
    }

}
As you can see, our OrderContext object wraps an instance of an OrdersDataContext object (via the _db field) which is a LINQ to SQL DataContext.  Therefore, our OrderContext object is essentially an abstraction of a LINQ to SQL data context.  When it implements the remaining IOrderContext interface members, it does this by making calls against that LINQ to SQL DataContext instance.
The OrderContext also wraps a TransactionScope object, which it only creates if the calling OrderRepository object specified that the context is transactional.  That transaction is committed in the CompleteTransaction method, which is required by the IContext base interface:
    void IContext.CompleteTransaction()
    {
        if (_ts != null)
            _ts.Complete();
    }
The last place we interact with this transaction is at the end of the order context object's lifecycle during the IDispose.Dispose implementation:
    void IDisposable.Dispose()
    {
        if (_ts != null)
            _ts.Dispose();
        _db.Dispose();
    }
We also dispose the OrdersDataContext which closes up the database connection.
So far with the OrderContext class we've implemented the creation and clean-up of the object.  Now we need to implement the methods defined by the IOrderContext interface that actually do the data access. 

IOrderContext.FetchInfoList Implementation

First, let's take a look at the implementation of the IOrderContext interface's FetchInfoList method:
    IEnumerable<IOrderInfoDto> IOrderContext.FetchInfoList()
    {
        var query =
            from o in _db.Orders
            orderby o.Date
            select new OrderInfoData
            {
                Id = o.Id,
                Customer = o.Customer,
                Date = o.Date
            };
        return query.Cast<IOrderInfoDto>();
    }

    private class OrderInfoData
        : IOrderInfoDto
    {
        public int Id { get; set; }
        public string Customer { get; set; }
        public DateTime Date { get; set; }
    }
The purpose of this method is to return a list of all the orders in the database.  They come back as the light-weight IOrderInfoDto objects.  Our implementation of this method performs a standard LINQ to SQL query against the Order entity objects in the OrdersDataContext.  However, we don't want to return all the data of each order.  The IOrderInfoDto object is only a subset of that data.  An easy solution is to perform a LINQ projection of Order objects to IOrderInfoDto objects.  This will generate only the T-SQL necessary to populate the data required by the IOrderInfoDto objects.  And of course we need a concrete IOrderInfoDto class to create and return; an easy approach is just to declare a private OrderInfoData class shown above just below the FetchInfoList method.

IOrderContext.FetchSingleWithLineItems Implementation

The next data access method required by the IOrderContext interface is FetchSingleWithLineItems:
    IOrderDto IOrderContext.FetchSingleWithLineItems(int id)
    {
        var options = new DataLoadOptions();
        options.LoadWith<Order>(o => o.LineItems);
        _db.LoadOptions = options;
        var query =
            from o in _db.Orders
            where o.Id == id
            select o;
        return query.Single();
    }
This method is similar to the previous in that it is another LINQ to SQL query.  However, it returns a single DTO (instead of a collection) and that DTO is an instance of the full Order entity class, which happens to implement the IOrderDto interface.
But we don't want to return just the data of the order itself.  We also want to return all of it's child line item data as well (which will be accessible via the LineItems property), and preferably all with one call to the database.  We can do this with a little LINQ to SQL magic by configuring the LoadOptions property of the OrdersDataContext, telling it that when it loads the data of an Order object, go ahead and load its child LineItem objects contained within the LineItems property.
The FetchInfoList and FetchSingleWithLineItems methods pretty much take care of all the data access querying.  Now we need to implement the insert, update, and delete operations. 

Insert, Update, and Delete Method Implementations

While the query method implementations simply took advantage of the built-in LINQ capabilities of the entity classes, we can't quite do the same with the insert, update, and delete methods.  Normally, with LINQ to SQL you can make whatever state changes you want to those objects and when you're ready to persist those changes back to the database, you just call the SubmitChanges method on the DataContext object, which keeps track of which entity objects have changed. 
While this approach could work in our situation, it requires us to maintain references to all of these objects between data access operations performed by our CSLA.NET business objects and this is a problem.  All CSLA.NET business objects need to be serializable so they can function properly in the CSLA.NET DataPortal.  This means that any objects contained within a CSLA.NET business object must also be serializable.  Unfortunately, LINQ to SQL objects are not.
There are some potential workarounds like one where you create a new LINQ to SQL entity object, load it with data, and then attach it to a DataContext as if it were previously fetched by the DataContext, but this is not using LINQ to SQL as it was intended and in many cases produces unexpected behavior.  The only reliable solution is to use a different mechanism than the LINQ to SQL entity objects and the DataContext to persist changes back to the database.  One of the easiest is the use of stored procedures.  This, in fact, is the same approach that Rocky uses with his LINQ to SQL data access code in his sample ProjectTracker application.  In the Orders.dbml file in our project, we simply drag those stored procedures over from the database and LINQ to SQL adds them as methods to the OrdersDataContext.
The last thing we should mention about the insert, update, and delete methods is that, unlike the query methods which returned DTO's (or collections of them), these methods take DTO's as parameters (except for delete which typically only takes an ID).  Therefore, the caller (in this case the CSLA.NET business object) needs to be able to create an empty DTO and populate it.  Which is why the OrderRepository class has the DTO creation methods. 
So, without further delay, here are the insert, update, and delete method implementations for the order entities:
    void IOrderContext.InsertOrder(IOrderDto newOrder)
    {
        int? id = null;
        Binary timestamp = null;
        _db.insert_order(
            ref id,
            newOrder.Customer,
            newOrder.Date,
            newOrder.ShippingCost, 
            ref timestamp);
        newOrder.Id = id.Value;
        newOrder.Timestamp = timestamp.ToArray();
    }

    void IOrderContext.UpdateOrder(IOrderDto existingOrder)
    {
        Binary newTimestamp = null;
        _db.update_order(
            existingOrder.Id,
            existingOrder.Customer,
            existingOrder.Date,
            existingOrder.ShippingCost,
            existingOrder.Timestamp, 
            ref newTimestamp);
        existingOrder.Timestamp = newTimestamp.ToArray();
    }

    void IOrderContext.DeleteOrder(int id)
    {
        _db.delete_order(id);
    }
We also have insert, update, and deletes for the line item entities as well, but they are very similar, so I'll save them for the sample code download at the end.

Sample Application

To make all of this really gel, I wanted to include a fairly extensive sample application that demonstrates everything we've been talking about in the last three posts: dependency injection and the Repository pattern with CSLA.NET.  However, this sample goes a bit further than what we've talked about so far so I wanted to briefly discuss it but save the details for an upcoming post.
A lot of what we've been building here are mechanisms to abstract each layer of our application so they are more loosely-coupled and more testable.  This is why dependency injection is so useful and why patterns like Repository really help.  But the Repository pattern is really just a means to abstract the data access layer.  What if you wanted to abstract the business layer?  What if you wanted to write unit tests that tested the functionality in your UI layer in isolation so that you wouldn't have to build concrete business objects in your tests?  That's the one big additional thing that the sample application sets out to do.  In short, it does this by defining abstractions (in the form of interfaces) for each business class and pulls out the static factor methods into separate factory interfaces and classes.
So here's a quick rundown of the projects that are included in the sample application solution, which is called CslaRepositoryTest:

  • DataAccess - contains the abstract data access layer interfaces
  • DataAccess.SqlServerRepository - a concrete implementation of the types in DataAccess
  • BusinessLayer - CSLA.NET business layer objects
  • BusinessLayer.Test - unit tests that test the business layer, mocking out the data access layer
  • Gui - a Windows Forms GUI that uses the business objects in BusinessLayer.  The GUI uses a Model/View/Presenter-style architecture so it can be more easily tested.
  • Gui.Test - unit tests that test the GUI layer, mocking out the business objects
  • Core - contains common types not necessarily specific to a particular layer
Some other notes:

  • The BusinessLayer is compiled against CSLA.NET 3.5.
  • The sample application uses v1.2 of the Unity Application Block as an IOC Container.  The Gui project configures uses a file called Unity.config to configure Unity.
  • The DataAccess.SqlServerRepository project uses SQL Server Express to attach to a file instance of the database, just like the CSLA.NET ProjectTracker sample application does.  The database file is Orders.mdf and is located in the same directory as the solution.
  • Both test projects use NUnit as their unit testing framework.  You should be able to run all of the unit tests in the NUnit-GUI application.
  • Both test projects use Rhino Mocks v3.5 for mocking objects.
  • The binaries for all of the 3rd party dependencies mentioned above are included in a lib folder in the download.  The only thing you need to have installed is Visual Studio 2008 and SQL Server 2005 Express (which usual comes with Visual Studio 2008).
Finally, here's the sample application.  (UPDATE: Changed link to point to my GitHub repo)

Conclusion

In this post we walked through a concrete implementation of our abstract data access layer that uses the Repository pattern.  Our implementation used LINQ to SQL, but we could have easily created one that used any other data access technology.  In an upcoming post, we'll dig a little further into how to abstract the business layer itself.

23 comments:

mamboer said...

It's really a awesome post!
Thumbs up!

Anonymous said...

Hello,the sample download link seems broken...

Pete said...

Hmm, just tried it and it's working. Try it again. I wonder if my web hosting provider was temporarily down.

~pete

Anonymous said...

This is was a great post I followed with great interest.

Any chance of seeing a CSLA 3.6.x version of this? Maybe using the Object Factory or at least handling the OnSerialized without the Context parameter.

Now that would make for a Framework. CSLA.Net, Unity(DI), Repository Pattern and EntLib 4.1 for Data Access (or whatever ORM you wish to use).

Thanks
Al

Pete said...

Al,

Thanks for the positive feedback. Makes all the work I put into writing it up more worth while.

I think there's a good chance you'll see a CSLA.NET 3.6 version of this very soon. We're actually using the CSLA.NET 3.5 code where I work now and we're about to migrate to 3.6 within the next month or so. I'll be sure make an update.

I'd also appreciate any enhancements you have to offer. I did mention in a previous post (where I discuss my general approach of using DI with CSLA.NET) the CSLA.NET 3.6 Object Factory. It has some potential, but it makes you do a lot more plumbing work for each business class. But I'm open to any suggestions.

Thanks!
~pete

Anonymous said...

Thanks a lot! Your post implemented exactly what I needed to decouple data access from the BO. It was my first use of Unity and I must say that I am very satisfied about the ease of use. Unit testing and integrated tests are also facilitated since I configure in unity.config a different repository depending of the type of tests I want to implement.

Two thumbs up!

Pete said...

Glad to hear the implementation worked for you! I find it interesting that you used the unity.config to drive your unit tests. While this is very doable, we ended up using mock objects for all of our tests, at least unit tests. In that case we just used Container.RegisterInstance to tell Unity to use the mock object when the interface was requested. However, I can see where using the unity.config to wire up special Repository objects for integration testing might be handy.

Anyway, I'd love to hear more about what you did.

~pete

Bernard said...

Well I've tried to implement a data layer that uses sprocs and not Linq, but I dont' get what the DataContext would be in that case.

Hope you have some pointers

Pete said...

The context would have the same role either way. The actual data access technology you use (LINQ, Sprocs, ADO.NET, etc) shouldn't matter. You still need an object that performs the actual data access, whatever that may be. Also, you can use LINQ to SQL (as well as LINQ to Entities) to call sprocs.

Bernard said...

I should have been more specific. I want to use good old ADO.NET.

When looking at the Linq solution, the DataContext is generated for you.

How do I mimic that for an ADO.NET solution I guess is the question.

I'm looking into Linq now and how it works with Sprocs. Looks like it will work, but I would like to get a standard ADO.NET DAL to work too....

Thanks for your time and efforts.

Pete said...

Ah, gotcha. I made the mistake of assuming that when you were talking about "DataContext" that you were referring to the more generic Context object in the Repository pattern framework I put together for these posts. But you're specifically talking about the LINQ to SQL DataContext. My apologies for the name confusion - it would have probably been more clear had I chosen a different name than Context. BTW - if you haven't read the previous post, I recommend it since it will give you some good background on the specific implementation of the Repository pattern that I use as well as some of the terminology.

So in the case of using this Repository pattern framework with LINQ to SQL, you're creating a Repository object and a Context object for each entity (the Order entity has OrderRepository and OrderContext in my example). However, if you're using LINQ to SQL you will have a LINQ to SQL DataContext that provides access to the actual database and it is contained within each Context object (OrderContext contains a OrdersDataContext which provides access to the Orders database). If there was another entity in the database, say Customer, then you'd have a CustomerRepository and CustomerContext and the CustomerContext would also contain a reference to the OrdersDataContext.

To adapt this to ADO.NET, you would simply change the OrderContext to make ADO.NET calls instead of LINQ to SQL calls. It wouldn't contain a reference to a LINQ to SQL DataContext, but rather a SqlConnection or SqlTransaction perhaps.

Hope this helps.

Bernard said...

I think I got it figured out.

The DataContext generated by Linq was the confusing part for me.

Once I associated that with a static AppProvider class then I think I got it.

I'll work on it in the morning.

I really appreciate this sample.

The one thing I can't get to work is to attach to the database you included...ther eis no lock file so the attach fails. Any ideas on that one.

Bernard said...

Why did you choose to have the repository just return new DTO's and not return DTO's via data access methods as well.

I've implemented the repository pattern before and we returned data from the database via the repository as well as new objects.

Just wondering why you did it this way?

-Bernie

Bernard said...

never mind. I see you pass the Context to the repository...I'll figure this out eventually

Bernard said...

Any idea what the Windsor Container equivalent of

InjectionMethod Attribute is.

Where I am at we have to use Windsor, unfortunately.

Thanks for your time

-Bernie

Pete said...

I'm not too familiar with Castle Windsor, but I do know it's a decent DI/IOC Container as there are many open source projects that use it (NHibernate I think does).

I don't think all DI frameworks support method-based injection and Windsor might be one of them. If it won't inject through a method, for CSLA.NET objects, you can also use property-based injection, which is usually more widely supported.

Anonymous said...

This is fantastic, congratulations!

Did you already have a chance to upgrade it to a newer version of csla?

Pete said...

We have upgraded. I just need to update the sample code for this post. However, it was pretty painless.

Anonymous said...

Hi Pete,

could you do me the favour and publish an upgraded version?

Kind regards
Heinz

James said...

Pete,
Are you still using this pattern with CSLA? Just wondering if you've found it to be solid and a good approach after utilizing it for a period of time.

Thanks for sharing your info!

Pete said...

James,

Yes we have for quite some time now. And I still need to get the version of this code out there that has been upgraded to the latest version of CSLA.NET.

~pete

Qiansong Cui said...

Hi Pete,

This sample code couldn't download. would you update it?

thanks.

Simon

Peter Stromquist said...

Sorry about the broken download for the sample code. Try it now!