Benny Michielsen

Entity Framework 4.1 – Change mappings at runtime

In v1 and v4 of EF I’ve been using this little gem, with a small tweak, to change the mappings of the model at runtime.

I was wondering how I could achieve something similar in version 4.1 code first. By design the OnModelCreating method is used to change the mappings of your model but it is only fired once per AppDomain since building it up does incur some performance penalty and normally your database schema does not change magically. In an application I’ve build though every customer gets his own tables, schemas etc. so hooking up some configuration logic in the OnModelCreating was out of the question since it’s only executed once.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //not possible, only executed once
    var tableName = _schemaService.LookupTheTableName(loggedInCustomer);
    modelBuilder.Entity().ToTable(tableName);
    base.OnModelCreating(modelBuilder);
}

Useless approach since the model isn’t being build again.

MvcApplication1Context myContext = new MvcApplication1Context(customer1, schemaService);
var csts = context.Customers.ToList();

//will go to the same tables as before, because OnModelCreating is only executed once
myContext = new MvcApplication1Context(customer2, schemaService);
var otherCsts = context.Customers.ToList();

There is a constructor though on the DbContext class that takes a compiled model and using that one does allow you to tweak the mappings you are using in your application. This also allows you to work with models that have been generated with a designer from 4.0 to use with the DbContext API.

//build config from scratch
DbModelBuilder builder = new DbModelBuilder(DbModelBuilderVersion.V4_1);
builder.Configurations.Add(new EntityTypeConfiguration());

//lets change something for each customer
var schemaName = schemaService.LookupTheTableName(loggedInCustomer);
builder.Entity().ToTable(schemaName);

//use the constructor that takes a compiled model
context = new MvcApplication1Context(builder.Build(context.Database.Connection).Compile());

You could then cache the compiled model for each customer so you don’t need to take that hit every time. Works like a charm. I’ll try to make it a bit easier to use.