Welcome to weblogs.com.pk Sign in | Join | Help

Real-world Entity Framework :: Mixing DbContext and ObjectContext

Entity Framework 4 had the POCO (Plain Old CLR/C# Object) support; but it was almost non usable. Things kept improving; there was once POCO T4 template (its walkthrough from ADO.NET team) to generate POCOs from EDMX model. With different 4.x releases introduced the DbContext API and Code First workflow; but there always had one hurdle; you couldn’t mix POCOs and EDMX generated entities in the single assembly. You will get EF Mapping and Metadata Information could not be found exception if you try to use POCO T4 template and Could not find the conceptual model type exception when you try to use DbContext and ObjectContext in single assembly; the reason was EDMX generated entities have certain attributes that Entity Framework runtime needs and when at runtime DbContext API generates the model from Code First classes; things get jumbled up.

This hurdle had been deal breaker for those having an existing projects where they are using one or more EDMX models; and wanted try out the DbContext API and Code First workflow; but given these two don’t mix and match nicely they couldn’t. In past; you either had to change all EDMXs to DbContext or not; but now with EF6; you can selectively change over to newer DbContext API. With recent open sourcing of Entity Framework in its v6; and their decision to bring out all the required underlying classes from .NET runtime to Entity Framework’s own assembly (which resulted change in the namespace so things don’t clash) enabled using the EDMX entities and POCO entities; mixing DbContexts and ObjectContexts; the trick is; keep your EDMX/Entity Contexts continues to use .NET Framework classes and use POCO entities with DbContexts from EF6 assembly; doing so things don’t get jumbled up!

  • When you add Entity Framework v6 from NUGET; it by defaults remove System.Data.Entity reference; re-add that so you can use EDMX/Object Context
  • As a best practice; I will suggest that think of it; as one time change; once you are on DbContext; stop using EDMX or better yet; delete the model and its designer file!
  • Don’t change the EDMX namespace in Visual Studio 2012; it prompts when you try to open the EDM file; as Visual Studio 2012 uses EF5 tools (and VS2013 uses EF6 tools) and they try to change the EDM namespace to use newer EF; we don’t want it; if we do so; things will not compile with Visual Studio 2010
  • Changing one or more EDMX/Object Contexts to POCO/DbContext need some more coding; the things we do in EDMX designer now needs to be done in POCOs or required Mappers; one such scenario is simulated below as reference

For the scenario; I made two EDMXes in a test app; then I migrated one model from ObjectContext (Vs2010/Box days) to DbContext (4.x and later); first I update the EF to EF6; using the NUGET and then added DbContext T4 generator; similar to what’s shown in the previous post. Think of these generated DbContext and POCO Entities as starting point; you will require to do some more work; don’t just delete the UnintentionalCodeFirstException from the OnModelCreating thinking its uselessly there! You will need to add required Mappers and disable Database initialization if working with existing database. In my test console app; I deleted the context T4 template and the associated CS file and move the code to my own file (Green box) where I will have the required Mappers and necessary changes in the generated DbContext; I can also delete the EDMX and its designer.cs file once I have my POCO entities; as I am intending to make all future additions/changes in my POCO classes using Code First / Code Migration workflows!

Context

Here’s the needed additions in the DbContext I had to do to start using my model!

class RecoveryEntities : DbContext
{
    static RecoveryEntities()
    {
       //We dont want EF to make changes in Db Schema
        Database.SetInitializer<RecoveryEntities>(null);
    }
 
    RecoveryEntities() { }
 
    public RecoveryEntities(string connectionString)
        : base(connectionString)
    {
    }
 
    public DbSet<RecoveryPaymentBatch> RecoveryPaymentBatches { get; set; }
    public DbSet<RecoveryPayment> RecoveryPayments { get; set; }
 
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //We are commenting this now; as we have done the required steps
        //throw new UnintentionalCodeFirstException();
        modelBuilder.Configurations.Add(new RecoveryPaymentBatchMap());
        //modelBuilder.Configurations.Add(new RecoveryPaymentMap());
        //and so on for other entities
    }
}
 
class RecoveryPaymentBatchMap : EntityTypeConfiguration<RecoveryPaymentBatch>
{
    public RecoveryPaymentBatchMap()
    {
        //EF works on convention; ours is bit different; so have to specify it
        //we could use data annotation attributes instead of map; but I like it more
        this.HasKey(t => new { t.BatchIndex });
 
        this.Property(t => t.BatchIndex)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

Notes

Published Wednesday, January 29, 2014 3:11 PM by khurram

Comments

No Comments

New Comments to this post are disabled