Note: This article applies to beta software and comes with no warranty or support, use at your own discretion. You must have Visual Studio.Net 2010 Beta 1 installed on your machine to make use of the code.
Update 25/06/2009: This article should be read first, however, see next article here which uses asp.net mvc and db4o object database with updated code now hosted at codeplex at http://kandaalpha.codeplex.com/ http://blog.keithpatton.com/2009/06/25/db4o+POCO+Repository+Using+Visual+Studio+2010+Net+40+Beta+1+And+ASPNet+MVC+10.aspx
Download KandaAlpha v1 Code Now
Before i delve into the details, it’s worth providing a bit of context on this post. For a number of years i’ve been a big fan of ORMs (object relational mappers) for helping get in memory software objects into and out of databases.
I’ve gradually moved away from a data-centric view of the world, towards a transition to domain driven design methodologies in architecting more complex enterprise applications.
My ORM of choice has up until around a year ago been NHibernate. I used it for a few years and grew to love it’s power and flexibility. But it always felt and still is a bit of a black art to make sing. And the tool and Linq support has never really matured to a level where i thought it was really going to take off.
Then along came the Entity Framework from Microsoft. I compared it and NHibernate during the .net 3.5 SP1 beta period and concluded that whilst it was architecturally inferior in many ways to NH, the availability of a designer, integrateion with Visual studio and .net combined with the sheer muscle of Microsoft dollars convinced me to give it a shot.
It was a success and saved me a lot of time, although i did have some pain taking EF across tiers usign web services, although the pain would likely have been there but in a different way with NHibernate. You can see some relatively popular previous posts are related to EF, with the Vote of Confidence in EF (in riposted to Alt.Net’s Vote of No Confidence) and also the code for the Polymorphic Repository for Entity Framework 1.0 (or what is now being called 3.5!).
And now we have Entity Framework 4.0. It is abundantly clear that the EF team have listened, learned and produced an ORM to be proud of. Whilst there will likely be gripes in various camps, we now have full POCO (plain old CLR object) support, lazy (deferred) loading support, AND model first design which allows us to create domain models and have the database generated from that. Very cool indeed.
So that’s the introduction. What i’m attempting to do at this early stage is to clearly demonstrate a DDD inspired layered architecture which combines a Repository pattern, injection of control (IoC) using the Microsoft Unity Application Block (swap out for your favourite IoC) and an Entity Framework 4.0 repository implementation.
Presented below are 4 logical layers, Presentation, Application, Domain and Infrastructure (a good overview of the DDD Layers). The rectangles are logical components within each layer (represented in code as .net assemblies). The full head arrows are runtime dependencies between the various libraries which sit within a particular layer. The dotted lines represent runtime dependency injection via our inversion of control tool of choice.
The Presentation Layer contains a web application (MVC wasn’t available in the Vs.net 2010 Beta 1 so I just used a ‘normal’ web application).
Then we have an Application Layer which has a class library of interfaces to define the behaviour of the implementing services which are in another class library. The services are injected using IoC as implementations of the application interfaces (we’ll see how that’s done later using Unity). The application layer co-ordinates requests from the presentation layer and makes use of the Repository in doing so.
The Domain Layer contains our Domain Model and Repository. The domain model has no dependencies to any other component or layer. The Repository consists of interfaces which define the behavior of the Repository implemented which is injected using IoC. The Repository represents a ‘store’ view of domain objects, underpinned by some form of persistence framework in the Infrastructure layer.
Lastly we have an Infrastructure Layer. In our example architecture this is the Entity Framework repository implementation and persistence framework. The class library has classes which implement the Domain’s Repository interfaces as well as having dependencies on the core EF classes and libraries.
Overall, this is a relaxed layered architecture in the sense that we have decent separate of concerns between the layers but we do allow cross layer dependencies. For example the domain model types are used within the web application (rather than have an extra layer of interfaces or data transfer objects).
The key point in this architecture is that the means by which domain objects are persisted is separated from the domain objects themselves. In addition, we have a Repository is defined within the domain layer, whilst its implementation is injected using IoC. The domain layer as a whole therefore has no awareness of or build dependency on the underlying persistence framework.
Here is the architecture represented as a Visual Studio.Net solution. You can see that I’m using Solution Folders to represent the various layers and then using class libraries for each layer component with the exception of the presentation layer which is represented by an asp.net web application. KandaAlpha is just a sandbox prefix I’m using.
For completeness please do note the Base Libraries folder which simply contains the IoC facade to the Microsoft Unity Application Block and also a references project housing the Unity application block dlls.
The Client Code
This first bit of code is the client api view at the asp.net web application level.
// get the customer service using IoC (Unity) var custService = IoCWorker.Resolve<ICustomerService>();
// get the customer repository from the customer service var custRepository = custService.GetRepository();
// get all customers and bind to grid dgCustomers.DataSource = custRepository.GetAll(); dgCustomers.DataBind();
// use a specific method on customer repository var kp = custRepository.GetBestCustomer();
// display customer's full name litCustomerName.Text = kp.FullName;
// demonstrate lazy/deferred loading (not for production!) litFirstOrderTotal.Text += kp.Orders.First().OrderTotal.ToString();
The basic idea here is that we request a service from the IoC container, and the service then provides the ability to fulfill a particular orchestration or unit of work.
You can see from the code that the ICustomerService implementation allows us to get a repository implementation to get all customers, to get the best customer, and also to get the first order total of the best customer. Note how lazy/deferred loading is working for the last call.
And hey presto, a very exciting screen is produced. (Note that the database is stored within App_Data in the web project. This would obviously be a remote SQL server in a production environment, i just wanted to provide the source fully contained)
Wiring up Unity IoC
Here’s how the inversion of control is wired up. See the containers element were we set up a single container and then set up the container to wire particular class implementations as singletons for each particular interface we are interested in providing a service implementation for. Take a look at the small KandaAlpha.Ioc.IocWorker static facade class which combined with configuration initialises the container and provides the hook into resolving service implementations for interfaces via the Resolve<T>() method.
<unity> <typeAliases> <!-- Lifetime manager types --> <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" /> <typeAlias alias="perThread" type="Microsoft.Practices.Unity.PerThreadLifetimeManager, Microsoft.Practices.Unity" /> <typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity" /> <!-- User-defined type aliases --> <typeAlias alias="ICustomerService" type="KandaAlpha.Application.Interfaces.ICustomerService, KandaAlpha.Application.Interfaces" /> <typeAlias alias="CustomerService" type="KandaAlpha.Application.Services.CustomerService, KandaAlpha.Application.Services" /> <typeAlias alias="IGenericRepository" type="KandaAlpha.Domain.Repository.IGenericRepository`1, KandaAlpha.Domain.Repository" /> <typeAlias alias="GenericRepository" type="KandaAlpha.Infrastructure.Repository.EF.GenericRepository`1, KandaAlpha.Infrastructure.Repository.EF" /> <typeAlias alias="ICustomerRepository" type="KandaAlpha.Domain.Repository.ICustomerRepository, KandaAlpha.Domain.Repository" /> <typeAlias alias="CustomerRepository" type="KandaAlpha.Infrastructure.Repository.EF.CustomerRepository, KandaAlpha.Infrastructure.Repository.EF" />
</typeAliases> <containers> <container name="containerOne"> <types> <type type="ICustomerService" mapTo="CustomerService"> <lifetime type="singleton" /> </type> <type type="IGenericRepository" mapTo="GenericRepository"> <lifetime type="singleton" /> </type> <type type="ICustomerRepository" mapTo="CustomerRepository"> <lifetime type="singleton" /> </type> </types> </container> </containers> </unity>
Domain Model
Nice, POCO classes, nothing relating to persistence or Entity Framework in here, just as it should be. All is right in the world;)
using System; using System.Collections.Generic;
namespace KandaAlpha.Domain.Model.Entities { public class Customer : EntityBase { public int CustomerID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string FullName { get { return FirstName + " " + LastName; } } public virtual List<Order> Orders {get; set;} } }
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace KandaAlpha.Domain.Model.Entities { public class Order : EntityBase { public int OrderID { get; set; } public Customer Customer { get; set; } public decimal OrderTotal { get; set; } } }
Domain Repository
So, IoC gives us an implementing class for ICustomerService which has a method GetRepository() which returns an ICustomerRepository implementation.
Leaving aside some of the wiring within the Application.Services component, let’s take a look a the ICustomerRepository interface defined within the Domain.Repository component
using System; using KandaAlpha.Domain.Model.Entities;
namespace KandaAlpha.Domain.Repository { public interface ICustomerRepository : IGenericRepository<Customer> { Customer GetBestCustomer(); } }
So, we have a single custom method on this repository, but most of the action is within the IGenericRepository<T>) class which defines our core repository behaviour as follows.
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using KandaAlpha.Domain.Model.Entities;
namespace KandaAlpha.Domain.Repository { public interface IGenericRepository<T> : IRepositoryBase where T : EntityBase {
/// <summary> /// Return strongly typed IQueryable /// </summary> IQueryable<T> GetQuery();
/// <summary> /// Load entity from the repository (always query store) /// </summary> /// <typeparam name="T">the entity type to load</typeparam> /// <param name="where">where condition</param> /// <returns>the loaded entity</returns> T Load(Expression<Func<T, bool>> whereCondition);
/// <summary> /// Provides explicit loading of object properties /// </summary> void LoadProperty(T entity, Expression<Func<T, object>> selector);
/// <summary> /// Returns all entities for a given type /// </summary> /// <returns>All entities</returns> List<T> GetAll();
/// <summary> /// Add entity to the repository /// </summary> /// <param name="entity">the entity to add</param> /// <returns>The added entity</returns> void Add(T entity);
/// <summary> /// Save all changes from repository to store /// </summary> /// <returns>Total number of objects affected</returns> int SaveChanges();
/// <summary> /// Mark entity to be deleted within the repository /// </summary> /// <param name="entity">The entity to delete</param> void Delete(T entity);
} }
As you can see from the Unity IoC configuration ICustomerRepository is wired up to CustomerRepository within the Infrastructure.Repository.EF component. You can see hopefully how you could modify this to be NHibernate, ADO.Net or an in memory provider for quick testing if needs be by just changing the IoC configuration.
EF Repository Implementation
The core job of the EF Repository implementation is to then implement the ICustomerRepository and IGenericRepository<T> interfaces.
The CustomerRepository and GenericRepository classes also make use of a static ObjectContextManager class. This implements a lifecycle management pattern across the EF’s object context which is one per http request (if HttpContext.Current is available) or one per thread for non web applications.
The EF’s edmx model class goes in this class library too. I followed the very simple instructions around how to enable POCO support for Entity Framework which largely entailed switching off code generation in the properties window of the edmx, nice!
Note the hand crafted KandaAlphaContext class which allows me to specify exactly what happens when the context gets created, including lazy loading options as follows:
public KandaAlphaContext() : base("name=KandaAlphaEntities", "KandaAlphaEntities") { _customers = CreateObjectSet<Customer>(); _orders = CreateObjectSet<Order>(); base.ContextOptions.DeferredLoadingEnabled = true; // lazy loading }
There is lastly an HttpRequestModule class which simply kills the object context at the end of each http request. For non web applications you would explicitly kill the context at the end of each unit of work. (although i haven’t yet got a facade method for that on the repository as yet).
Summary
I’m a big fan of the new Entity Framework. I think that the EF team are going to get this release spot on and we’ll see Entity Framework really establish itself as the ORM of choice for Microsoft developers. It will be interesting to see what the Alt.Net community make of EF v2 (sorry v4!), but from what i can see they’ve hit all the right buttons this time around. We’ll likely be talking about specific features, or sql optimisation as opposed to core architectural gripes this time around i feel.
As a big NHibernate fan too, I’m disappointed that Microsoft can’t co-opt more proven open source software like with JQuery as it’s a real boon to the .net community to have these projects flourish.
Powered by: newtelligence dasBlog 1.9.6264.0
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
© Copyright 2013, Keith Patton
E-mail