Code First Building Blocks

There are plenty of examples out there showing how to use DbContext to create a Code First model. But DbContext itself uses some fundamental Code First building blocks to do its stuff. This post shows how these building blocks can be used directly, which can be useful in situations where you need more control over how the model is created or cached.

When would you do this?

DbContext can be used in the normal way for most applications. However, there are currently two areas for which we get quite a few questions where the best approach is to fall back to using the lower-level building blocks.

The first area is caching of the model. DbContext caches the model based on the type of your context. For example, if you have a context class called BlogContext, then DbContext will build the model once the first time it is used and for subsequent uses the cached model will be used. This doesn’t work if you have one context type but want to use it with different models.

The second area is direct control over the type of database that the model will target. DbContext creates a connection to the database to determine appropriate mappings. For example, if the database is SQL Server 2008, then mappings for types only available in SQL Server 2008 might be used. If you need the model to also work with SQL Server 2005, then you’ll need to tell Code First explicitly to do this.

It’s a river rock thing…

The paragraphs above describe concrete situations in which in makes sense to use the Code First building blocks. However, the main reason the building blocks are there is to account for situations we haven’t anticipated. The building blocks provide flexibility to Code First allowing it to be used in new and interesting ways.

Let’s do it!

Let’s take this very simple model and context as an example:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

Normally you would use the context like this:

using (var context = new BlogContext())
{
    context.Blogs.Add(new Blog { Name = "One Unicorn" });
    context.SaveChanges();
}

When the context is used for the first time (in the Add call above) it will normally go through the process of building the model. Let’s instead see how this can be done using the lower-level building blocks.

It’s all about DbModelBuilder

Building a Code First model always starts with an instance of DbModelBuilder. You’ve probably seen DbModelBuilder in the OnModelCreating method. This is where DbContext gives you access to the model builder it is using to create a model. To use the lower-level building blocks you create the DbModelBuilder directly:

var builder = new DbModelBuilder();

Once you have a model builder you need to give it some starting points to discover the model. This is done by calling the Entity method on the model builder:

builder.Entity<Post>();
builder.Entity<Blog>();

DbContext normally does this for you by looking at the DbSets you have declared on your context and calling the Entity method for each of these.

Some other things to note here:

  • You don’t need to call Entity for every entity type in your model. Code First follows references in the types it is given and so will discover all the model that is reachable from the types you give it. For example, in the code above calling Entity for only Blog or only Post would result in the same model because Post is reachable from Blog and vice versa.
  • You can also use the ComplexType method to tell the builder about complex types.
  • You can create EntityTypeConfiguration and ComplexTypeConfiguration instances and add them to the builder instead of calling the Entity/ComplexType methods.
  • You can provide additional configuration starting from each Entity call using the fluent API just as you would when overriding OnModelCreating

Building the model

Once you have the model builder configured you need to build the model. This is where you have more options using the building blocks. DbContext normally builds the model in this way:

var model = builder.Build(connection);

As described above, this uses the given connection to connect to the database and determine appropriate mappings. If, for example, you want to explicitly tell Code First to build a database for SQL Server 2005, then you would instead build the model in this way:

var model = builder.Build(
    new DbProviderInfo("System.Data.SqlClient", "2005"));

The DbModel instance returned by the Build method is an object model representation of the underlying Entity Data Model (EDM). Unfortunately as of EF5 this EDM object model is not exposed publicly, so the DbModel instance is opaque. We intend to make this object model public in EF6, but as with anything that hasn’t happened yet, that could change. Once it is public you will be able to manipulate the EDM directly to tweak the model created by Code First.

Compiling the model

The EDM object model isn’t used directly by DbContext while the app runs, so it first needs to be compiled into a form that can be used. To do this call the Compile method:

var compiledModel = model.Compile();

For EF geeks, the DbCompiledModel returned is currently a thin wrapper around a MetadataWorkspace, but this may not always be the case.

Caching the compiled model

The DbCompiledModel instance is the thing that DbContext caches. When using these building blocks you should find a way to cache the compiled model in your app. Likewise, do your own caching of the compiled model instances in situations where you need to use multiple models with the same context type.

Using the compiled model

Once you have a compiled model it’s easy to use it with DbContext—just pass an instance to the appropriate constructor. You’ll need to modify your context class to allow this:

public class BlogContext : DbContext
{
    public BlogContext(DbCompiledModel model)
        : base(model)
    {
    }

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Posts> Posts { get; set; }
}

And then call it where you use the context:

using (var context = new BlogContext(compiledModel))
{
    context.Blogs.Add(new Blog { Name = "One Unicorn" });
    context.SaveChanges();
}

DbContext will then use the given model instead of going through the process of creating one itself.

What about pluggable conventions?

Code First has a pluggable system for the conventions used to build and configure the model. Unfortunately, as of EF5 this system is internal. As with the EDM object model we intend to make this system public in EF6. (Disclaimer: as I said above, this is our intention, but things are not set in stone and it could change.)

Summary

By using the DbModelBuilder directly you can take more control over the way your Code First model is created and cached. In the future we will add additional interception/extensibility points such as a public EDM object model and pluggable conventions to provide even more control.

About Arthur Vickers

Developer on the Entity Framework team at Microsoft.
This entry was posted in Code First, Entity Framework and tagged , , , , , , . Bookmark the permalink.

10 Responses to Code First Building Blocks

  1. shawson says:

    Great aticle- very helpful. I’m trying to implement this myself so I can execute stored procedures against sql 2005 (http://stackoverflow.com/questions/15924635/entity-framework-5-tsql-not-compatible-with-sql-2005-calling-stored-procedures) – I think your article may be the key, however I can’t figure out how I supply a DbProviderInfo and the connection the builder.Build() method?

    • I see from Stack Overflow that you got this working. I’ll just point out that in EF6 it is much easier to set the provider manifest token to always be “2005”. You can implement the IManifestTokenService and register it using code-based configuration in a DbConfiguration class. Doing this means that you can still use DbContext in the normal way without having to do everything with the low-level building blocks.

      • Graham says:

        Sorry to ask this after so long, but how exactly do you do this – there seems to be little if any documentation for this area.

      • @Graham What is it that you want to do?

      • Graham says:

        Hi Athur, I’ve got a problem with a deployed application that’s calling stored procedures via Entity Framework 6 (Code First – but the database already exists). On my test system, everything’s fine, but on the deployed version it falls over when it calls the stored procs, and I suspect it’s due to the database on the server being SQL 2005 – I have SQL 2012 on development. Like @shawson above, I think I need to be able to tell it to use SQL 2005 syntax, but I’m not sure what your comment means as regards setting this up via a DbConfiguration class. Can you give me an example class and how to set this up? Any help would be greatly appreciated.

      • @Graham See http://msdn.microsoft.com/en-us/data/jj680699 for general info on DbConfiguration. Implement IManifestTokenResolver with something like


        public class MyResolver : IManifestTokenResolver
        {
        public string ResolveManifestToken(DbConnection connection)
        {
        return "2005";
        }
        }

        Add your implementation of IManifestTokenResolver in your DbConfiguration:


        public class MyConfig : DbConfiguration
        {
        public MyConfig()
        {
        SetManifestTokenResolver(new MyResolver());
        }
        }

        Hope this helps,
        Arthur

      • Graham says:

        Hi Arthur,
        Many thanks for pointing me in the right direction on this. I implemented what you suggested, and breakpoints showed that the config does get executed, but unfortunately I still have the problem. Entity Framework emits this SQL, for example:

        exec sp_executesql N’GetInternalPurchaseOrders @OrderNo, @Account, @IncludeLines’,N’@OrderNo nvarchar(5),@Account nvarchar(4000),@IncludeLines bit’,@OrderNo=N’12345′,@Account=N”,@IncludeLines=0

        which executes happily on SQL 2012 but SQL 2005 throws the exception “syntax error near ‘GetInternalPurchaseOrders'”. I understand from various comments I’ve seen that this is due to SQL 2005 not liking variable declarations and initialisations in the same statement, but I’ve seen no solution to this as yet. As a result, I’ve had to rework parts of my code to use standard ADO.NET SQL data readers, which is less than ideal, until I find a fix or work around.

        Thanks for your help,
        Graham

      • @Graham Where did the stored proc come from? Did you have Migrations create it or was it created outside of EF?

      • Graham says:

        @Arthur, this is an existing database and the stored proc was already there. I’d like to get rid of it to be honest and just access the data using EF, but this is currently not possible as the procedure also gets some data from another database (which I don’t like either!), so I’m stuck with it at the moment.

  2. Dejan S says:

    >> var model = builder.Build(
    >> new DbProviderInfo(“System.Data.SqlClient”, “2005”));

    This should not be strings.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s