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<Customer>().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<Customer>());
 
//lets change something for each customer
var schemaName = schemaService.LookupTheTableName(loggedInCustomer);
builder.Entity<Customer>().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.

Entity Framework 4.1 – Supporting Enums

One of those features you think are so trivial are hard to miss if you use that latest new tool. One of those is enum support in Entity Framework 4.1, just like in all other versions of the framework it just isn’t there.

There is though a way to get around it, unfortunately it does mean changing your model just a tiny bit.

In the sample class model I used for my previous posts on mapping inheritance each movie had an enum value to hold its media type, DVD, Bluray,…

You won’t see it mapped by default in your database if you use Entity Framework 4.1 out of the box. So having the enum property there isn’t enough, you have to explicitly add an int property like below.

[Required]
public virtual EMediaType MediaType { get; set; }
 
public virtual int MediaTypeId
{
    get { return (int)MediaType; }
    set { MediaType = (EMediaType)value; }
}

And change your model mapping a bit inside your DbContext class if needed.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     modelBuilder.Entity<Movie>()
        .Property(x => x.MediaTypeId)
        .HasColumnName("MediaType")
        .IsRequired();
 
    base.OnModelCreating(modelBuilder);
}

You can still use the enum property in the rest of your application, which I encourage.

NuGet – install all packages referenced by a project

When you install packages in a project using NuGet you probably don’t want to include those in your version control system. When you want to share some code in a blogpost you don’t want to include all the dlls that are referenced by your project since people can install the packages through NuGet.

When you install a package though a file gets added called packages.config containing all information needed by NuGet to find it in the repositories. There’s no out of the box solution though all the hooks are in place. You need to install the package called “NuGet.CommandLine”.

This allows you to issue the nuget command which lets you refer to the packages.config file. Then use your package console manager to issue the following command: “nuget i PathToConfig -o Packages”.

You’ll see all your packages fly by. You can find more info over here.

Entity Framework 4.1 Inheritance – Table per Concrete Type

There’s one more way to implement the sample domain model in the database and that’s a table for each class with all properties. And unfortunatly our luck ends a bit here. Although it’s possible to generate an ERD that looks like what we want to achieve I need to change the domain model.

You get the database model above by using the following mapping code

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Movie>()
        .Map(x =>  x.MapInheritedProperties())
        .ToTable("Movies");
    modelBuilder.Entity<Cd>()
        .Map(x => x.MapInheritedProperties())
        .ToTable("Cds");
    modelBuilder.Entity<Book>()
        .Map(x=> x.MapInheritedProperties())
        .ToTable("Books");
 
    base.OnModelCreating(modelBuilder);
}

Pollymorphic associations though are not supported using this inheritance strategy and so you need to omit the collection of products in the category class, bummer.

public class Category
{
    [Required]
    public virtual Guid Id { get; set; }
    [Required]
    public virtual string Name { get; set; }
    //public virtual IList<Product> Products { get; set; }
}

Entity Framework 4.1 Inheritance – Table per Type

Using the same model as before, we want to store it more in a normalized fashion and in my opinion something that closely resembles a typical inheritance structure in code.



Lets create one table for each entity with only the properties it contains, all other ones are linked through a one to one mapping. To achieve this result you’ll need to create your mappings as illustrated below.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Movie>().ToTable("Movies");
    modelBuilder.Entity<Cd>().ToTable("Cds");
    modelBuilder.Entity<Book>().ToTable("Books");
    base.OnModelCreating(modelBuilder);
}

Entity Framework 4.1 Inheritance – Table per Hierarchy

By default if you apply inheritance in Entity Framework 4.1 the model that will be used is table per Hierarchy. Meaning that this object model:Will be translated to this table in your database:

So we get one table containing all the fields from all the classes in the hierarchy and one additional discriminator column which will be filled with the name of the class. Using that value EF knows what class it needs to create an instance from. Create a mapping for this manually would be done by subclassing DbContext and implement OnModelCreating as illustrated in the following piece of code:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .Map(x => x.ToTable("Products"))
        .Map<Book>(x => x.ToTable("Products"))
        .Map<Movie>(x=>x.ToTable("Products"))
        .Map<Cd>(x => x.ToTable("Products"));
    base.OnModelCreating(modelBuilder);
}

Entity Framework 4.1 Material

Gave a quick intro on what’s new in entity framework 4.1 to my co-workers. You can get the slides and the code.

If you want to get started documentation is at the moment a bit lacking, there is some info on MSDN but you’ll find more on the ADO.NET team blog, especially this 12 part article.

Yesterday the power tools for Entity Framework 4.1 were released, you can read all about them over here.

There are some features that didn’t make it into Entity Framework code first but that are available if you use one of the “older” approaches, Microsoft is quite open about it, which I think is very honest. You can read about those on the MSDN site as well.

There’s also some material that was available in the latest CTP material but didn’t ship in 1.0. Let’s hope they’ll come in the next release.

MVC3 and MonoDevelop

Just a quick update to list the assemblies you need to copy to make MVC3 work with Mono and MonoDevelop. On my Mac I opened a Visual Studio solution, I deleted all the entity framework references from my MVC project, won’t use it anyway, and then copied these assemblies to a local folder since they are not part of the Mono framework:

  • System.Web.Helpers
  • System.Web.Mvc
  • System.Web.Razor
  • System.Web.WebPages.Deployment
  • System.Web.WebPages
  • System.Web.WebPages.Razor

Fix the references in your project, hit run and you’re good to go. Unfortunately you’re not getting any intellisense yet.