简体   繁体   English

EF代码优先:继承的dbcontext创建两个数据库

[英]EF code first: inherited dbcontext creates two databases

I'm trying to create a base dbcontext that contains all the common entities that will always be reused in multiple projects, like pages, users, roles, navigation etc. 我正在尝试创建一个基本dbcontext,其中包含所有常用实体,这些实体将始终在多个项目中重用,如页面,用户,角色,导航等。

In doing so I have a ContextBase class that inherits DbContext and defines all the DbSets that I want. 这样做我有一个ContextBase类继承DbContext并定义我想要的所有DbSet。 Then I have a Context class that inherits ContextBase where I define project specific DbSets. 然后我有一个Context类继承ContextBase,我定义项目特定的DbSet。 The classes are defined as follows: 这些类定义如下:

public class ContextBase : DbContext
{
    public virtual DbSet<User> Users { get; set; }
    //more sets

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UsersConfiguration());
        //add more configurations
    }
}


public class Context : ContextBase
{
    public DbSet<Building> Buildings { get; set; }
    //some more project specific sets

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Configurations.Add(new BuildingsConfiguration());
        //add more project specific configs
    }
}

In my global.asax: 在我的global.asax中:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());

where Configuration referes to a class inheriting DbMigrationsConfiguration and overriding the Seed method. 其中Configuration引用继承DbMigrationsConfiguration并重写Seed方法的类。

The two context classes are defined in the same namespace, but cross assembly (in order that I may update the base project in multiple existing projects without touching the project specific code) - not sure if this is relevant. 两个上下文类在同一名称空间中定义,但是交叉程序集(为了我可以在多个现有项目中更新基础项目而不触及项目特定代码) - 不确定这是否相关。

MY PROBLEM: When running this code, it works fine, but when looking in the Database, it actually creates two different databases!! 我的问题:运行此代码时,它工作正常,但在查看数据库时,它实际上创建了两个不同的数据库! One containing all the base entity tables and one containing BOTH base and custom tables. 一个包含所有基本实体表,另一个包含BOTH基表和自定义表。 CRUD operations are only performed on the custom version (which is obviousely what I want), but why does it create the schema of the other one as well? CRUD操作只在自定义版本上执行(这显然是我想要的),但为什么它也会创建另一个版本的模式?

Any help is appreciated, thanks! 任何帮助表示赞赏,谢谢!

UPDATE: 更新:

The following code is what I ended up with. 以下代码是我最终得到的。 It isn't ideal, but it works. 它并不理想,但它确实有效。 I would still love to get feedback on ways to improve this, but in the meantime I hope this helps further the process. 我仍然希望获得有关如何改进这一点的反馈,但与此同时,我希望这有助于推动这一进程。 I REALLY DO NOT RECOMMEND DOING THIS! 我真的不推荐这样做! It is extremely error prone and very frustrating to debug. 它非常容易出错并且非常令人沮丧。 I'm merely posting this to see if there is any better ideas or implementations to achieve this. 我只是发布这个,看看是否有更好的想法或实现来实现这一目标。

One (but not the only) issue still existing is that the MVC views have to be manually added to projects. 仍然存在的一个(但不是唯一的)问题是必须手动将MVC视图添加到项目中。 I've added it to the Nuget package, but it takes 2 to 3 hours to apply a nuget package with so many files when VS is connected to TFS. 我已经将它添加到Nuget包中,但是当VS连接到TFS时,需要2到3个小时来应用具有如此多文件的nuget包。 With some more work and a custom View engine the views can be precompiled ( http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html ). 通过一些更多工作和自定义View引擎,可以预编译视图( http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html )。

The solution is split into the Base Framework projects and the Custom projects (each category includes its own models and repository pattern). 该解决方案分为Base Framework项目和Custom项目(每个类别包括自己的模型和存储库模式)。 The framework projects are packaged up in a Nuget package and then installed in any custom projects allowing the common functionality of any project like user, role and permission management, content management, etc (often referred to as the Boiler Plate) to be easily added to any new projects. 框架项目打包在Nuget包中,然后安装在任何自定义项目中,允许任何项目的常用功能,如用户,角色和权限管理,内容管理等(通常称为Boiler Plate)轻松添加到任何新项目。 This allows any improvements of the boilerplate to be migrated in any existing custom projects. 这允许在任何现有的自定义项目中迁移样板的任何改进。

Custom Database Initializer: 定制数据库初始化器:

public class MyMigrateDatabaseToLatestVersion : IDatabaseInitializer<Context>
{
    public void InitializeDatabase(Context context)
    {
        //create the base migrator
        var baseConfig = new FrameworkConfiguration();
        var migratorBase = new DbMigrator(baseConfig);
        //create the custom migrator
        var customConfig = new Configuration();
        var migratorCustom = new DbMigrator(customConfig);

        //now I need to check what migrations have not yet been applied
        //and then run them in the correct order
        if (migratorBase.GetPendingMigrations().Count() > 0)
        {
            try
            {
                migratorBase.Update();
            }
            catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException)
            {
                //if an error occured, the seed would not have run, so we run it again.
                baseConfig.RunSeed(context);
            }
        }
        if (migratorCustom.GetPendingMigrations().Count() > 0)
        {
            try
            {
                migratorCustom.Update();
            }
            catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException)
            {
                //if an error occured, the seed would not have run, so we run it again.
                customConfig.RunSeed(context);
            }
        }
    }
}

Framework's DB Migrations Configuration: Framework的数据库迁移配置:

public class FrameworkConfiguration: DbMigrationsConfiguration<Repository.ContextBase>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    public void RunSeed(Repository.ContextBase context)
    {
        Seed(context);
    }

    protected override void Seed(Repository.ContextBase context)
    {
        //  This method will be called at every app start so it should use the AddOrUpdate method rather than just Add.

        FrameworkDatabaseSeed.Seed(context);
    }
}

Custom Project's DB Migrations Configuration: Custom Project的数据库迁移配置:

public class Configuration : DbMigrationsConfiguration<Repository.Context>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    public void RunSeed(Repository.Context context)
    {
        Seed(context);
    }

    protected override void Seed(Repository.Context context)
    {
        //  This method will be called at every app start so it should use the AddOrUpdate method rather than just Add.

        CustomDatabaseSeed.Seed(context);
    }
}

The custom DbContext 自定义DbContext

//nothing special here, simply inherit ContextBase, IContext interface is purely for DI
public class Context : ContextBase, IContext
{
    //Add the custom DBsets, i.e.
    public DbSet<Chart> Charts { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //Assign the model configs, i.e.
        modelBuilder.Configurations.Add(new ChartConfiguration());
    }
}

Framework DbContext: 框架DbContext:

//again nothing special
public class ContextBase: DbContext
{
    //example DbSet's
    public virtual DbSet<Models.User> Users { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder);
}

In the global.asax AppStart: 在global.asax AppStart中:

        //first remove the base context initialiser
        Database.SetInitializer<ContextBase>(null);
        //set the inherited context initializer
        Database.SetInitializer(new MyMigrateDatabaseToLatestVersion());

In the web.config: 在web.config中:

<connectionStrings>
    <!--put the exact same connection string twice here and name it the same as the base and overridden context. That way they point to the same database. -->
    <add name="Context" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/>
    <add name="ContextBase" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/>
</connectionStrings>

(from the comments) (来自评论)

You're creating ContextBase objects directly, apparently as new T() in a generic method with ContextBase as a generic type argument, so any initialisers for ContextBase also run. 您正在直接创建ContextBase对象,显然是在使用ContextBase作为泛型类型参数的泛型方法中的new T() ,因此ContextBase任何初始化程序也会运行。 To prevent creating ContextBase objects (if it should never be instantiated directly, if the derived context should always be used), you can mark the class as abstract . 要防止创建ContextBase对象(如果永远不应该直接实例化,如果应始终使用派生的上下文),则可以将该类标记为abstract

你的ContextBase似乎也有一个初始化器。你可以删除它

Database.SetInitializer<ContextBase>(null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM