;

Persistence Ignorant POCOS part 5 – EntityFramework CodeFirst

Posted : Sunday, 03 April 2011 21:32:50

This is the final post in a series comparing the developer experience of wiring up an existing application to use some of the more popular ORM tools out there. In this post I will adapt the LightsCameraAuction application to use EntityFramework version 4.1 – specifically CodeFirst. CodeFirst has been developed following community feedback generated in response to the earlier iterations of EntityFramework – notably the rather complex process required to wire up EntityFramework to an existing database (see post 2 in this series) and in my opinion the far more restrictive requirement to derive all Entities from a single base class – e.g. the lack of POCO support. CodeFirst allows POCO CLR classes to be persisted, change tracked and life-cycle managed by the EntityFramework. This is achieved via the use of new lightweight version of the ObjectContext class called DbContext. As well as POCO support, CodeFirst also supports a fluent mapping interface thereby offering the double bonus of providing compile-time validation as well as XML free configuration. So enough chat lets dive in….

I created a new class library project called LcaModel.CodeFirst with the required class structure yada yada yada….

project

I then added a reference to the EntityFramework – I would normally use NuGet to do this but I wasn’t online when I wrote this post and had a copy of the necessary assembly on my machine so I copied it to my solution directory and added a reference to this assembly (EntityFramework.dll).

The code for the EfCodeFirstModule class is pretty much the same as earlier posts so I haven’t shown it but it simply tells Ninject to use the EfCodeFirstxxxxxxRepositories in the application. One thing to note is that whereas the EntityFramework implementation(see post #2) required a different version of the connection string containing details of the mapping data, CodeFirst is happy to use a generic connection string (POCS?) so I used the same one as in the last two posts. Launching the app now gave, as expected, a NotImplementedException due to the boilerplate code generated via the VisualStudio “Implement Interface” context menu option.

everything in place

As mentioned above, in CodeFirst persistence is managed via a DbContext derived class. I added a new class called EfCodeFirstContext and exposed a DbSet<T> strongly-typed to each of my POCO classes, DbSet<T> implements IQueryable<T> and is the means by which CodeFirst provides access to the persisted entities (in a real world application you would typically expose one DbSet per aggregate root). To each of my repositories I added a constructor accepting a connection string and stored this connection string in a private class level field. I then added “the code to do the things”– I’ve shown the code for EfCodeFirstBidderRepository below, as you will notice its pretty similar to the other implementations.

    7 namespace LcaModel.EfCodeFirst
    8 {
    9     public class EfCodeFirstBidderRepository : IBidderRepository
   10     {
   11         private string _connectionString;
   12 
   13         public EfCodeFirstBidderRepository(string connectionString)
   14         {
   15             _connectionString = connectionString;
   16         }
   17 
   18         public void Add(LcaModel.Bidder bidder)
   19         {
   20             using (var context = new EfCodeFirstContext(_connectionString))
   21             {
   22                 context.Bidders.Add(bidder);
   23                 context.SaveChanges();
   24             }
   25         }
   26     }
   27 }
   28 

Now running the code resulted in the following message.

no_mapping

Not quite as user-friendly as some of the other ORMs but given that there was no mapping yet it was pretty evident what the problem was – no mapping! As with Fluent NHibernate, mapping is achieved via a fluent interface which is accessible through an override on the DbContext derived class. Its pretty straightforward to use this interface and I’ve shown an excerpt below.

   24         protected override void OnModelCreating(DbModelBuilder modelBuilder)
   25         {
   26 
   27             modelBuilder.Entity<Bidder>()
   28                 .HasKey(x => x.BidderId)
   29                 .ToTable("bidder");
   30 
   31             modelBuilder.Entity<Bidder>()
   32                 .Property(x => x.BidderId)
   33                 .HasColumnName("bidder_id");
   34 
   35             modelBuilder.Entity<Bidder>()
   36                 .Property(x => x.Name)
   37                 .HasColumnName("bidder_name");
   38 
   49             //...other POCO mappings not shown
   40 
   41         }

During the course of completing the mapping I made a few mistakes and the error messages CodeFirst returns are, as in the case of the no-mapping exception above, pretty confusing…

ef_mapping_problem

I say confusing as in this case all my POCOs had foreign-key properties and the InnerException was null!

After a bit of fiddling with the association mapping, LightsCameraAuction was up and running using CodeFirst as the persistence mechanism – WOOHOO!

efcf_running

And as usual Barney won – it seems that the motto of the whole auctioneering process process should be Bid Early Bid Often (is there a snappier way of expressing that?)

In summary I have to say getting an EntityFramework CodeFirst implementation of LightsCameraAuction running was a breeze. The mapping interface was nice and developer friendly (although the error messages not so much) and the methods exposed by the DbContext class make it very easy to work with. Of all the implementations in this series EntityFramework and LinqToSql both proved very fiddly to map due to their XML based configurations – it should be said they do both offer alternative mapping strategies (attributes and/or partial classes) but using them would violate the persistence ignorance goal of this exercise! Fluent NHibernate and CodeFirst were very easy to implement and provided a comparably positive developer experience. In its current state CodeFirst is very much the new kid on the block and still has a few issues to resolve (Stored Procedure support etc.) but it promises to evolve and mature into a very stable solution. NHibernate has been around for a while and has great community support and the fluent interface is very nice to work with. While LightsCameraAuction is only a very simple application it provided a great platform on which to implement a range of persistence strategies. Writing this series of posts has been both enlightening and satisfying and provided me with a better insight of just what persistence ignorance means and how to achieve it – I hope you find it of some use. Please post any comments or email me with any questions.

  • (This will not appear on the site)