powered by Slim Framework
enhanced by Nesbot.com

ASP.NET: Entity Framework's Code-First with an ObjectContext

Published on Apr 30, 2012 by Jamie Munro

If the following blog interests you, it's probably because you're using Entity Framework with a Code-First approach and whatever it is you are trying to do *must* use an ObjectContext instead of the standard DbContext.  I'm sure, like me, you thought this shouldn't be too hard.  Then you started hitting roadblocks like, Metadata is required in your connection string.  What's metadata?  This is only needed in Database-First so you can tell the framework where your edmx and other definition files are, so why do I need this with Code-First, I don't have these files?

This was definitely my first reaction as well.  So after much trial-and-error and research, I have the solution!


 To understand how the solution came about, it's important to understand one of the key differences between ObjectContext and DbContext.  In the scenario above, it's to do with the metadata.  A DbContext is an extension of ObjectContext and is intelligent enough to build its own metadata from either the code or the database.  However, ObjectContext is not that smart, it must be strictly supplied the metadata.  With Database-First this is easy because the edmx file does this for us.  However, with Code-First, it's not.

At first glance this doesn't make sense either, aren't my Code-First models definitions enough?  Yes and no.  Yes, they are, but not without a few extra lines of code first!

Enough chit-chat, let's get down to the solution.  For this example, I have created a new MVC application and added the Entity Framework via the NuGet package manager.

Next, for cleanliness only, I created a new Domain class library that will house my models and context files.

Inside of this project, I have the following files (also be sure to add the Entity Framework to this project as well):


Now on to the code, I typically like to create an AppModel for generic properties to share amongst all models:


namespace Domain.Models
{
public class AppModel
{
public long Id { get; set; }
}
}


Next, I created three different models that create a many-to-many relationship, Country, Language, and CountryLanguages.

Country.cs:


namespace Domain.Models
{
public class Country : AppModel
{
public string Name { get; set; }
}
}


Language.cs:


namespace Domain.Models
{
public class Language : AppModel
{
public string Name { get; set; }
}
}


CountryLanguage.cs:


namespace Domain.Models
{
public class CountryLanguage : AppModel
{
public Language Language { get; set; }
public Country Country { get; set; }
}
}


Now, I need to create an extension of the ObjectContext which will contain ObjectSet's for the above models.  This is contained in the PersistenceContext.cs:


using System;
using System.Collections.Generic;
using System.Data.Entity;
using Domain.Models;

namespace Domain.Persistence
{
public class PersistenceContext : DbContext
{
private readonly Dictionary<Type, object> _dbSets = new Dictionary<Type, object>();

public PersistenceContext(EntityConnection connection) : base(connection)
{

}

private IObjectSet<T> GetDbSet<T>() where T : AppModel
{
if (!_dbSets.ContainsKey(typeof(T)))
{
_dbSets[typeof(T)] = Set<T>();
}

return _dbSets[typeof(T)] as IDbSet<T>;
}

public IObjectSet<Country> Countries {
get { return GetDbSet<Country>(); }
}

public IObjectSet<Language> Languages {
get { return GetDbSet<Language>(); }
}

public IObjectSet<CountryLanguage> CountryLanguages {
get { return GetDbSet<CountryLanguage>(); }
}
}
}


At this point, I honestly thought I should be able to begin using this objects; however, I was quite wrong.  One crucial piecing is still missing.  It is contained in the Utils/AppConfig.cs file:


using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using Domain.Models;

namespace Domain.Utils
{
class AppConfig
{
public static DbModelBuilder GetBuilder()
{
DbModelBuilder builder = new DbModelBuilder();
builder.Entity<EdmMetadata>().ToTable("EdmMetadata");

builder.Entity<Language>();
builder.Entity<Country>();
builder.Entity<CountryLanguage>();

return builder;
}
}
}


A new DbModelBuilder must be created that creates the metadata for the ObjectContext to understand how the data is defined.  As you can see, I have one builder.Entity<> per model.

The final piece of the puzzle is to actual create a new context and add and query the data.  I created a new HomeController.cs in my Controllers folder with the following code:


using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Domain.Models;
using Domain.Persistence;
using Domain.Utils;

namespace MvcApplication2.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/

public void Index()
{
var connectionString = @"Server=.\SQLEXPRESS;Database=PersistenceContext;Trusted_Connection=true";
DbModelBuilder builder = AppConfig.GetBuilder();
DbConnection connection = new SqlConnection(connectionString);
DbCompiledModel model = builder.Build(connection).Compile();

PersistenceContext context =  model.CreateObjectContext<PersistenceContext>(connection);

var temp1 = context.Languages.ToList();
var temp2 = context.Countries.ToList();
var temp3 = context.CountryLanguages.ToList();

context.Dispose();
connection.Dispose();
}
}
}


In the above code the following is done:

  1. Create a new connection to a local Sql Express database.

  2. Create a new DbModelBuilder that contains the metadata definition of the database.

  3. Create a new SqlConnection with the connection string.

  4. Create a new DbCompiledModel with the compiled metadata from the builder.

  5. Create a new PersistenceContext by calling the CreateObjectContext from the compiled metadata and connection.


That's it, Code-First using an ObjectContext!

Summary


The missing LINQ, I mean link, has been found to use ObjectContext and Entity Framework's Code-First approach.  The key ingredient is a DbModelBuilder with one Entity<> per model in your application defined.  Stay tuned for more Entity Framework fun!

Tags: ASP.NET | mvc3 | entityframework | objectcontext | dbcontext

<- CSS3: Creating Diagonal Lines  Home  
blog comments powered by Disqus