Posts tagged ‘CodeFirst’

I’ve been writing a lot more integration tests for my recent projects in which I’ve made use of Entity Framework. I’m purely using code first as I never really got along with the whole draggy droppy designer affair. I came to realise recently that I was writing an awful lot of code to mock out my data layer (using Moq). But all I was really doing was making sure that my Linq queries pulled back the correct data. Even after having gone to all the effort I was still getting problems with my code when it got to see a database for the first time. Usually to do with me doing things which cannot be converted in to T-SQL. So I’ve decided to ditch unit testing and mocking for any data layer stuff and go totally over the integration testing. Making the move to entity framework code first has made that very simple. First off I create a couple of “self-creating” properties for my Context and Repository.

    private DomainContext _context;
    protected DomainContext Context
    {
        get { return _context ?? (_context = new DomainContext(ConfigurationManager.ConnectionStrings["ByBox"].ConnectionString)); }
        private set { _context = value; }
    }

    private ConsumerRepository _repository;
    private ConsumerRepository Repository
    {
        get { return _repository ?? (_repository = new ConsumerRepository(Context)); }
        set { _repository = value; }
    }

Then I have some straight forward setup/teardown code. All this usually ends up in a base class of some kind which I re-use in all my different test source files.

    [TestFixtureSetUp]
    public virtual void TestFixtureSetUp()
    {
        try
        {
            var seed = new DomainDataSeed();
            Database.SetInitializer(seed);
            Context.Database.Initialize(true);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            throw;
        }
    }

    [TestFixtureTearDown]
    public virtual void TestFixtureTearDown()
    {
        Repository.Dispose();
        Repository = null;
        Context.Dispose();
        Context = null;
    }

Another useful thing to do is to be able to reset the database to a know state. You may have noticed these 3 lines above …

            var seed = new DomainDataSeed();
            Database.SetInitializer(seed);
            Context.Database.Initialize(true);

What these do is use a data seed class to initialise the database. By way of example, here is a snippet from my seed class …

    public class DomainDataSeed : DropCreateDatabaseAlways<DomainContext>
    {
        protected override void Seed(DomainContext context)
        {
            AddWebServiceUsers(context);
            AddUserAccounts(context);

            context.SaveChanges();
        }

        private void AddWebServiceUsers(DomainContext context)
        {
            context.Database.ExecuteSqlCommand("CREATE TABLE [web_service_user] ( ... )");
            context.Database.ExecuteSqlCommand("CREATE TABLE [web_service_user_attribute] ( ... )");
            context.Database.ExecuteSqlCommand("INSERT INTO [web_service_user] ([username], [password]) values({0}, {1})", Username, Password);
        }
        private static void AddUserAccounts(DomainContext context)
        {
            context.UserAccounts.Add(
                new UserAccount
                    {
                        ...
                    });
        }
    }

If I wanted to I could put that code into the [SetUp] method rather than the [TestFixtureSetUp] method. Or, as I have done recently in a ResetDatabase() method, which I call from the [TestFixtureSetUp] and select tests as required. This particular seed class drops and re-creates the database every time it is called, thanks to this – DropCreateDatabaseAlways<DomainContext>. There are other options available, including only dropping and re-creating the database (and seeding it) when the model changes.

I recently wrote about how to Automatically Add Framework Config Classes to the Model Builder. Since writing that post I have come across a situation where I was writing the exact same model class in a different application. That just didn’t smell right to me, since the other applications data access layer had been packaged up by nuget I could simply add a reference to it. That’s all well and good, but I didn’t want to have to go to any special effort to add the model configuration classes I needed to my modelbuilder. So, I’ve created a fairly simple (although it’s taken me a while to get it working how I want it) base class from which I can derive my context classes.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Base.EntityFramework
{
    public abstract class BaseDbContext : DbContext
    {
        protected BaseDbContext() { }
        protected BaseDbContext(string connectionString) : base(connectionString) { }

        private IEnumerable<Type> GetTypes()
        {
            var type = typeof(EntityTypeConfiguration<>);
            return GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(p => p.PropertyType.IsGenericType &&
                            p.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>))
                .Select(p => type.MakeGenericType(p.PropertyType.GetGenericArguments().First()))
                .ToArray();
        }

        private static void LoadAllEntityConfigurationsFromAllAssemblies(DbModelBuilder modelBuilder, IEnumerable<Type> types, string assemblyFilter, IEnumerable<string> namePartFilters)
        {
            var path = Path.GetDirectoryName((new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
            new DirectoryCatalog(path, assemblyFilter)
                .LoadedFiles
                .Where(x =>
                {
                    var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(x.ToLower());
                    if (fileNameWithoutExtension != null)
                    {
                        var parts = fileNameWithoutExtension.Split(".".ToCharArray());
                        return parts.Any(part => namePartFilters.Any(namePartFilter => part == namePartFilter.ToLower()));
                    }
                    return false;
                })
                .Select(Assembly.LoadFrom)
                .ToList()
                .ForEach(assembly => assembly.GetTypes()
                                         .Where(t => types.Contains(t.BaseType))
                                         .Select(Activator.CreateInstance)
                                         .ToList<dynamic>()
                                         .ForEach(instance => modelBuilder.Configurations.Add(instance)));
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            var typesToLoad = GetTypes();
            LoadAllEntityConfigurationsFromAllAssemblies(modelBuilder, typesToLoad, "*.dll", new[] { "Data", "Domain" });
        }

    }
}

and in english ….

  1. Discover which classes for which I need to find and load the relevant EntityTypeConfiguration<> class. This is done with a little bit of reflection in the GetTypes() method.
  2. Use MEF to find the assemblies the config classes might be in. In this case it’s all of them (*.dll), but that could be changed to whatever is best for your situation.
  3. Use the namePartFilters to narrow down the list of assemblies further. In this case I’m looking for anything with “Data” or “Domain” in the filename (after it’s been split by periods).
  4. Load each assembly.
  5. Load any generic EntityTypeConfiguration types for the model classes used within my context class (the one which is derived from this base class).
  6. Instantiate each config class.
  7. Add it to the modelBuilder’s configurations.

Since this is a base class I can get this behaviour whenever I derive from it ….

    public class DomainContext : BaseDbContext, IDomainContext
    {
        public IDbSet<Employee> Employees { get; set; }

        public DomainContext() { }
        public DomainContext(string connectionString) : base(connectionString) { }

        IQueryable<Employee> IDomainContext.Employees { get { return Employees; } }
    }

What this allows me to do is use models from any assembly I am referencing in my application and just add it to my Context. Any configuration class for it will then be automatically added to the model builder.

I should start off by saying this isn’t my code, I copied it from somewhere, but I cannot remember where. So, if you know send me a comment and I’ll update this post accordingly.

One of my pet peeves with entity framework code first, is having to add all my config classes to the modelBuilder within my context, like so….

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UserConfig());
        modelBuilder.Configurations.Add(new TitleConfig());
        modelBuilder.Configurations.Add(new UserTitleConfig());
    }
}

But that’s a real PITA. I don’t want to have to remember to add every config class in that method every time I extend my model. It also starts to become untidy very quickly.

namespace MyProject
{
    public class MyContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            Assembly.GetExecutingAssembly().GetTypes()
                .Where(type => type.Namespace == "MyProject.Config")
                .ToList()
                .ForEach(type =>
                         {
                             dynamic instance = Activator.CreateInstance(type);
                             modelBuilder.Configurations.Add(instance);
                         });
        }
    }
}

That’s better! Now I can forget about that minor detail and get on with creating my model. I’ve used the namespace of the type to limit the scope to just my “config” folder. You may want to do it some other way or even choose not to limit it in any way.

EDIT (13 Dec 2011)

I have since found a better way of filtering the types to load …

                .Where(type => type.BaseType != null &&
                               type.BaseType.IsGenericType &&
                               type.BaseType.GetGenericTypeDefinition() == typeof (EntityTypeConfiguration<>))