【问题标题】:Forcing code-first to always initialize a non-existent database?强制代码优先始终初始化一个不存在的数据库?
【发布时间】:2012-10-04 09:33:07
【问题描述】:

有时,我会删除我的开发数据库并运行我的 EF 代码优先应用程序。我会得到错误:

无法打开登录请求的数据库“AssessmentSystem”。登录失败。 用户“AssessmentAdmin”登录失败。

我认为这是因为DbContext 仅在“第一次使用上下文时每个 AppDomain 一次”运行 DB 初始化逻辑,正如this page 所说。这意味着如果我删除它,我需要回收 IIS 应用程序池以让 EF 重新创建我的数据库。

有什么方法可以让数据库初始化代码运行每次我尝试访问数据库?因此,它会始终检查数据库是否存在,如果不存在,则创建它而不是尝试打开它,即使它使用之前访问我现在删除的数据库的同一个 AppDomain?

请注意,我希望对每个查询都进行这种初始化检查,因此即使在Application_Start 中完成它也不够;理想情况下,我希望能够加载一些数据库数据,删除数据库,然后加载一些数据库数据,它会重新创建数据库,而我什至不必重新启动应用程序(基本上我只需要重新加载网页加载一些数据库数据)。

【问题讨论】:

    标签: sql-server-2008 entity-framework ado.net ef-code-first


    【解决方案1】:

    Initializer 在您需要访问数据库时执行,因此如果您想在应用启动时创建数据库,请使用以下任何内容:

        context.Database.Initialize(true); //If set to true the initializer is run even if it has already been run.       
        context.Database.Create()
    

    http://msdn.microsoft.com/en-us/library/system.data.entity.database.initialize(v=vs.103).aspx

    CreateDatabaseIfNotExists IDatabaseInitializer 的实现,仅当数据库不存在时,它将重新创建并选择性地使用数据重新播种数据库。要为数据库播种,请创建一个派生类并覆盖 Seed 方法。

    Database.SetInitializer<MyContext>(new CreateDatabaseIfNotExists<MyContext>());
    

    http://msdn.microsoft.com/en-us/library/gg679221(v=vs.103).aspx

    DropCreateDatabaseIfModelChanges IDatabaseInitializer 的一个实现,仅当模型在创建数据库后发生更改时,才会删除、重新创建和可选地使用数据重新播种数据库。这是通过在创建时将存储模型的散列写入数据库,然后将该散列与从当前模型生成的散列进行比较来实现的。要为数据库播种,请创建一个派生类并覆盖 Seed 方法。

    初始化策略可以选择检查数据库 存在,创建一个新数据库,并为数据库播种数据。这 默认策略是 CreateDatabaseIfNotExists。

    Database.SetInitializer(new DropCreateDatabaseIfModelChanges());

    请注意,这假设您有权删除您的数据库。

    http://msdn.microsoft.com/en-us/library/gg679604(v=vs.103).aspx

    DropCreateDatabaseAlways

    IDatabaseInitializer 的一种实现,在应用程序域中第一次使用上下文时,它总是会重新创建并选择性地为数据库重新播种数据。要为数据库播种,请创建一个派生类并覆盖 Seed 方法。

    Database.SetInitializer<MyContext>(new DropCreateDatabaseAlways<MyContext>());
    

    http://msdn.microsoft.com/en-us/library/gg679506(v=vs.103).aspx

    如果您想跟踪,我建议您查看 Migrations,将您对数据库所做的更改恢复到以前的状态 http://msdn.microsoft.com/hr-hr/data/jj591621

    更新

    context.Database.Initialize(true);
    

    如果参数 force 设置为 true,则运行初始化程序 不管它之前是否运行过。这可以是 如果在应用程序运行时删除数据库并且需要 重新初始化。

    对于 MVC 应用程序,在 Global.asax

    Application_Start() 方法中添加一个部分
    protected void Application_Start() {
    
         Database.SetInitializer<MyContext>(new DropCreateDatabaseAlways<MyContext>()); 
    
         // Forces initialization of database on model changes.
         using (var context= new MyContext()) {
              context.Database.Initialize(force: true);
         }    
    }
    

    您也可以使用自定义初始化程序:

    public class MyDbInit : DropCreateDatabaseAlways<MyContext>
    {
    
    }
    

    然后使用

    Database.SetInitializer(new MyDbInit());
    

    更新 2

    创建一个名为 DeleteDBOnEveryRequest 的新空 MVC4 应用程序。 将以下内容放入 Global.asax Application_start

    protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
    
                WebApiConfig.Register(GlobalConfiguration.Configuration);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
    
                Database.SetInitializer<BlogContext>(new DropCreateDatabaseAlways<BlogContext>());    
    
                using (var context = new BlogContext())
                {
                    context.Database.Initialize(force: true);
                }    
            }
    

    创建一个名为 DatabaseController 的新控制器,其中包含两个操作。

    Access 操作中,您删除数据库并重定向到 Recreated 操作,您可以从该操作中创建以前删除的数据库。

    namespace DeleteDBOnEveryRequest.Controllers
    {
        public class DatabaseController : Controller
        {
            public ActionResult Access()
            {
                using (var context = new BlogContext())
                {
                    context.Database.Delete();
                } 
                return RedirectToAction("Recreated");
            }
    
            public ActionResult Recreated()
            {
                using (var context = new BlogContext())
                {
                    context.Database.Initialize(force: true);                
                }
                return View();
            }
        }
    }
    

    这是你想要的吗?

    【讨论】:

    • 否; Initializer 仅在第一次使用上下文时每个 AppDomain 运行一次。如果数据库不存在,我希望初始化它任何时候我尝试访问它,即使该上下文之前已用于访问数据库
    • 那么,如果您进行的每个查询都不存在数据库,您想重新创建它吗?
    • 是的。 (stackoverflow 需要这个额外的文本,否则我无法发表评论)
    • 这很好,99% 在那里,但它仍然只适用于应用程序启动。虽然这通常足够好,但如果有一个解决方案,我加载一个访问数据库的页面,删除数据库,然后重新加载该页面并重新创建数据库,那就太好了。实际上,我需要对应用程序代码进行一些更改以在启动之前触发应用程序启动(我承认这仍然比以前好得多)。
    • 我目前不在电脑前,所以请给我一个小时左右的时间来为您提供解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-01-20
    • 2018-09-27
    • 2011-10-10
    • 2013-07-04
    • 2015-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多