Wednesday, 18 May 2011

Entity Framework 4.1: Riding the Magic Unicorn

UPDATE: there is now a VS2013 version of the sample project.

Although it was released back in April, it’s taken me until now to actually try out Entity Framework 4.1 (aka Magic Unicorn).  It’s very impressive and does a surprisingly large amount of the work of getting data from databases and putting it into objects (and vice versa) without the need for visual designers (although they’re still there) or field-by-field mapping.  The only bad thing I can say about it is that for something so feature-rich, documentation is thin on the ground, so I shall add what I’ve learnt to the scant body of knowledge out there.  Other than ADO.NET team blog, most of what I didn’t work out myself came from the invaluable Morteza Manavi’s blog – so I won’t repeat what’s already there.
To provide a little context (no pun intended), what drew me to EF 4.1 was the possibility of mapping an existing database to an existing object model.  This, to my mind, is the way that ORM should be done – i.e. you create a data schema according to the best practices of relational design, create an object model based on the domain requirement, then use ORM to get them to talk to one another.  Basically I think you should design object models with your OOP developer hat and design data schemas with your DBA hat.  Although there may be similarities between the two models, it’s rare that they’ll be exactly the same.
Anyway, I’ve spent this week mapping a complex object model to an equally complex data structure and despite thinking (at times) that Magic Unicorn didn’t support the type of mapping I was attempting, it proved me wrong on all counts and happily transformed my data schema into my object model.  I’ve also done some tinkering with EF across WCF, but I won’t bring that into the mix just yet as it comes with a whole load of caveats and scariness.

The basics

It’s worth mentioning that if your objects have the same name as the tables they map to and your properties have the same name as the fields, then you don’t need to do much at all.  EF will automatically infer the mappings based on a set of conventions – all you have to do is create the DbContext.  This is all covered by Scott Gu’s blog post.  The only caveat is that all POCOs you want to persist must have a key field.
In order to do custom mapping you have to override the OnModelCreating method of the DbContext and use EF’s fluent API to set up the mappings.  Most of the examples out there put all the mapping rules in the OnModelCreating method like so (I’ve included the DbContext setup for clarity):
public class MyDatabaseContext : DbContext
{
 public MyDatabaseContext()
  : base("data source=(local);initial catalog=MyDatabase;integrated security=True")
 { }

 public DbSet<MyClass> MyClasses { get; set; }

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
  modelBuilder.Entity<MyClass>()
   .Property(c => c.SomeFieldOrOther)
   .HasColumnName("StrangelyDifferentFieldName");
  modelBuilder.Entity<MyClass>()
   .Ignore(c => c.AFieldIDontWantMapped);
 }
}
I prefer to use an EntityTypeConfiguration class as it’s cleaner and more maintainable.  Basically you create one EntityTypeConfiguration for every class on which you want custom mapping and put the mapping code in the constructor:
public class MyClassEntityTypeConfiguration : EntityTypeConfiguration<MyClass>
{
 public MyClassEntityTypeConfiguration()
 {
  Property(c => c.SomeFieldOrOther).HasColumnName("StrangelyDifferentFieldName");
  Ignore(c => c.AFieldIDontWantMapped);
 }
}
Then add a new instance of that class to the DbContext’s configurations (via the OnModeCreating method), like so:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
 modelBuilder.Configurations.Add<MyClass>(new MyClassEntityTypeConfiguration());
}
You can add in as many entity type configurations as you like, but if you don’t add one for a class then the default mapping rules will apply.
As an aside, something worth noting in the above examples is the use of the Ignore() method. This is used because any property in a class that doesn’t map to a field in the database must be explicitly ignored (except for enumerations which are ignored by default).

The example models

The sample project for this can be downloaded here.
For illustration I will use the scenario of a product sales LoB system.  Let us imagine that we have a company that uses field sales people to sells widgets.  The sales people can make either a sales or support visit to a customer – the model for this is shown below:
Visit model
Although the data model is probably close to what I’d actually use in such a situation, I have intentionally designed it to be ‘awkward’ via the use of differently named fields/properties, schemas, odd relationships etc:
Sales sample ERD

The code

In this section I’ll just explain a couple of the tricks I’ve used to get the mapping done.  Although the sample project includes mapping of object hierarchies I won’t bother explaining this as it’s covered better elsewhere.
  • Enumerations
    UPDATE: Later versions of EF do this natively. Don't use the code below.
    If you want to coerce a numeric value into an enumeration then just expose the database field as a numeric property and get the property setters to do the work for you.  In the sample, I’ve done this on the Visit class using the following enumeration:
    public enum VisitTypes : short
    {
    Sales = 1,
    Support = 2
    }
    The enumeration property ‘Type’ gets its value from the ‘VisitTypeId’ property (which maps to the field of the same name in the database).
    public class Visit
    {
     private short? _visitTypeId;
     private VisitTypes? _type;
    
     public VisitTypes? Type
     {
      get
      {
       return _type;
      }
      set
      {
       _type = value;
       _visitTypeId = null;
    
       if (_type.HasValue)
       {
        _visitTypeId = (short)_type.Value;
       }
      }
     }
    
     public short? VisitTypeId
     {
      get
      {
       return _visitTypeId;
      }
      set
      {
       _visitTypeId = value;
       _type = null;
    
       if (_visitTypeId.HasValue)
       {
        VisitTypes visitType;
    
        if (Enum.TryParse<VisitTypes>(_visitTypeId.ToString(), out visitType))
        {
         _type = visitType;
        }
       }
      }
     }
    }
    By using the Enum.TryParse method we can ensure that any values in the database that don't match the ones available in the enumeration force the enum field to null.
  • Multiple tables into one object
    This has been done in the SupportCheckList class in the sample. Simply call the Map method for every table that you want to include, using the ToTable and Properties methods in the lambda expression:
    public SupportChecklistEntityTypeConfiguration()
    {
     HasKey(s => s.Id);
    
     Map(m =>
      {
       m.ToTable("SupportCheckList", "Data");
       m.Properties(s => new
       {
        s.Id,
        s.WasIssueFixedDuringVisit,
        s.HasCustomerBeenGivenFollowUpDate
       });
      });
    
     Property(s => s.Id)
      .HasColumnName("SupportCheckListId")
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
     Map(m =>
      {
       m.ToTable("SupportCheckListSafety", "Data");
       m.Properties(s => new
       {
        s.HasProductBeenMadeSafe,
        s.ProductFailureCausedIncident
       });
      });
    }
    The Properties method takes an anonymous type which contains a list of the fields which are mapped from the given table. You can then do column mapping as per normal (outside of the Map method) and EF will know where to look for the field.
    If you want to get multiple objects into one table then have a look at this post.
I won’t explain the various cardinality mappings because it’s quicker just to look at the sample.  There’s a mass of odd relationships and strange keys that I’ve put in there purposely to show how to use the Map() method of the fluent API.

Monday, 16 May 2011

MSMQ and WCF across the Internet

I've learned two new things in the last week about WCF or, to be more accurate, I have had two of my foolish assumptions corrected. The first assumption was that MSMQ provides support for disconnected interoperable services, while the second was that I would never need to self-host a WCF service in a Windows Forms/WPF application. Happily I now have a test application that does both of these things, thus giving me a pattern for what used to be called a "smart client".

Both of these discoveries came about as part of a project to deliver an occasionally-connected application for tablet devices. Basically, the client application would collect a load of data, package it up into a DTO, then persist it via a WCF service. Given the never-ending CTP state of the Sync Framework and my preference for SOA over the client/server database approach, I thought MSMQ would facilitate a single programming model regardless of the connectivity status of the client - simply designate the appropriate WCF service methods as one-way calls and expose over an MSMQ endpoint.

The problem with this is that MSMQ doesn't do what I thought it did. I assumed that I could expose a service endpoint somewhere "out there", then the MSMQ local queue on the client would monitor the availability of a network connection and post messages in the local queue off to the service when connectivity was achieved. This works very nicely in public queues, but they require an Active Directory installation and can't be exposed outside of the Intranet. A private queue (in a workgroup installation) can only post to/monitor an MSMQ service on the same machine. I did consider a bespoke solution using Isolated Storage, serialization, and a timer control - but it didn't have the transactional reliability of MSMQ (and had all the hallmarks of a badly reinvented wheel).

The answer to my problem came from the oft-quoted bible of WCF: Juval Lowy's "Programming WCF Services", where he addresses the issue of MSMQ over the Internet by means of the HTTP bridge pattern (p.518) and also the bit where he discusses responsiveness when hosting WCF services in a UI application (p.416). My solution is to post all messages into a local private queue, then trap the network connectivity events in the System.Net.NetworkChange class and launch/shutdown (as appropriate) a local MSMQ service host in the UI application (which must have the UseSynchronizationContext value on the ServiceBehavior attribute set to true so as not to lock up the UI thread). When the local MSMQ service starts up it sends all messages to the distant (HTTP) service using the bridge pattern. If the send fails (or any other unhandled exception occurs) then the local MSMQ service gets faulted and shuts down. It will start up again either the next time the network status active event is raised or when the application is opened again (the only problem with this approach being that if the call to the distant service fails because of a problem with the service itself then the call could well fail again the next time the local MSMQ service gets launched - but this doesn't lead to lost messages so I can live with it).

The sequence of activity is something like:

  • Form startup
  • Create queue (if it doesn't exist) on a background thread
  • When background worker returns set up event handler for NetworkAvailabilityChanged
  • If a network connection is available then launch the MSMQ service
  • If the network connection becomes unavailable then shut down the service
  • If the service faults then shut it down
  • If the network connection becomes available then launch the service

Getting an exception to fault the service host is done in the binding configuration:

<bindings>
<netMsmqBinding>
<binding receiveErrorHandling="Fault" 
receiveRetryCount="0">
<security mode="None"/>
</binding>
</netMsmqBinding>
</bindings>

This will stop any retries after the fault occurs. Subscribing to the Faulted event on the service host will provide a hook for taking action after a fault occurs.

The sample project can be downloaded here.  It requires MSMQ workgroup installation, which can be reached by the following route:

  1. On Windows XP this can be enabled by going into Control Panel, Add Remove/Programs, Add/Remove Windows Components.
  2. In Vista/Windows 7 this can be enabled by going into Control Panel, Programs, Turn Windows features on or off.

Run the sample, disable your network adapter, make a call, then enable your network adapter – it should send the messages queued locally.  It’ll need to be run in debug mode as the distant service simply writes out to the Debug/Output window, but it should be sufficient implementation for illustration.