Update model causes interface to be removed from DbContext when using Effort with Entity Framework


Question

Presently, I am attempting to use Effort (https://effort.codeplex.com/) with my Entity Framework 6 solution to allow unit testing without requiring a database connection (see http://www.codeproject.com/Articles/460175/Two-strategies-for-testing-Entity-Framework-Effort). Everything works in my project, where this is the DbContext with an interface and the overloaded constructors required for Effort:

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Data.Common;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class HRADDbContext : DbContext, IHRADDbContext
    {
        public HRADDbContext() : base("name=HRADDbContext")
        {
        }        

        public HRADDbContext(string nameOrConnectionString)
            : base(nameOrConnectionString)
        {
            this.Configuration.LazyLoadingEnabled = false;
        }

        public HRADDbContext(DbConnection connection)
            : base(connection, true)
        {
            this.Configuration.LazyLoadingEnabled = false;
        }

        public virtual DbSet<CCS_DEPT_TBL> CCS_DEPT_TBL { get; set; }
        public virtual DbSet<CCS_HR_AD_SYNC> CCS_HR_AD_SYNC { get; set; }
    }
}

The problem is, if I update the .edmx file by choosing "Update model from database..." then it regenerates the context file to be:

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Data.Common;
    using System.Data.Entity;

    public partial class HRADDbContext : DbContext
    {
        public HRADDbContext() : base("name=HRADDbContext")
        {
        }        

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<CCS_DEPT_TBL> CCS_DEPT_TBL { get; set; }
        public virtual DbSet<CCS_HR_AD_SYNC> CCS_HR_AD_SYNC { get; set; }
    }
}

So I have to go back and manually update the above Context.cs file every time. Also, removes the [Key] from the POCO CCS_DEPT_TBL file.

Is there any way to setup my Entity Framework project so that it doesn't blow away the interface and overloaded constructors every time I update the model from the database? TIA.

UPDATE:

Since the class is partial, I just ensure that the interface and overloaded constructors are put in a separate file that is not auto-generated.

UPDATE 2:

OK, got it, just added this as a separate file, taking the DEPTID out of the original POCO file, but it still puts that DEPTID in the generated file, so after an update the build breaks because there are two DEPTID values in the same class:

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

    public partial class CCS_DEPT_TBL
    {
        [Key]
        public string DEPTID { get; set; }
    }
}

So, how do I prevent it from generating DEPTID in the generated class file, since it is already in the above partial class file?

Accepted Answer

Yes, the class is defined as a partial class. Create a new file that also declares the same partial class and add your additional methods there.

As for the [Key] attribute being lost, you can try and use a MetadataType attribute and put all your meta data there.

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

    [MetadataType(typeof(CCS_DEPT_TBL_Meta))]
    public partial class CCS_DEPT_TBL
    {
      ... Your additional constructors and methods here ...
    }
    public class CCS_DEPT_TBL_Meta
    {
        [Key]
        public string DEPTID { get; set; }    
    }
}

Popular Answer

Thank you @Robert McKee! Here is what I ended up doing:

CCS_DEPT_TBL_Key.cs:

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    [MetadataType(typeof(CCS_DEPT_TBL_Meta))]
    public partial class CCS_DEPT_TBL
    {

    }
    public class CCS_DEPT_TBL_Meta
    {
        [Key]
        public string DEPTID { get; set; }    
    }
}

CCS_DEPT_TBL.cs:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Collections.Generic;

    public partial class CCS_DEPT_TBL
    {
        // This table in SQL Server does not have a primary key, it just has an index
        public string DEPTID { get; set; }
        public string DESCR { get; set; }
        public System.DateTime EFFDT { get; set; }
        public string EFF_STATUS { get; set; }
        public Nullable<System.DateTime> LASTUPDDTTM { get; set; }
    }
}

HRModel.Context.cs: The HRADDbContext is actually database-first entities, but there are three other *.edmx files that are code-first entities in the same project, so commented out this exception in HRModel.Context.cs because it doesn`t apply. It would probably be better to separate out the database-first entities into a separate project so this exception would not be generated on a database model update.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class HRADDbContext : DbContext
    {
        public HRADDbContext()
            : base("name=HRADDbContext")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<CCS_DEPT_TBL> CCS_DEPT_TBL { get; set; }
        public virtual DbSet<CCS_HR_AD_SYNC> CCS_HR_AD_SYNC { get; set; }
    }
}

HRADDbContext.cs, where the IHRADDbContext interface is necessary for Effort:

using System;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

namespace Cssd.IT.PortalIntegration.DataAccess.HR.Dao
{

    /// <summary>
    /// Added interface here so that it does not get removed when updating 
    /// model from the database on code generation.
    /// </summary>
    partial class HRADDbContext : IHRADDbContext
    {
        public HRADDbContext(string nameOrConnectionString)
            : base(nameOrConnectionString)
        {
            this.Configuration.LazyLoadingEnabled = false;
        }
        public HRADDbContext(DbConnection connection)
            : base(connection, true)
        {
            this.Configuration.LazyLoadingEnabled = false;
        }
    }
}




Licensed under: CC-BY-SA
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why