【问题标题】:Database in use error with Entity Framework 4 Code FirstEntity Framework 4 Code First 的数据库使用错误
【发布时间】:2011-07-14 10:11:27
【问题描述】:

我有一个 MVC3 和 EF 4 Code First 应用程序,它被配置为在模型更改时更改 DB,方法是将 DB Initializer 设置为 DropCreateDatabaseIfModelChanges<TocratesDb>,其中 TocratesDb 是我派生的 DbContext

我现在通过向类添加属性来更改模型,但是当 EF 尝试删除并重新创建数据库时,我收到以下错误:

Cannot drop database "Tocrates" because it is currently in use.

我在此数据库上绝对没有任何其他连接打开。我假设我的 cDbContext 仍然与数据库有一个打开的连接,但是我能做些什么呢?

新: 现在我的问题是如何根据模型重新创建数据库。通过使用更通用的 IDatabaseInitializer,我失去了它并且必须自己实现它。

【问题讨论】:

  • 这发生在我身上,因为我正在针对数据库调用 Membership 方法,这会造成冲突。我通过在使用会员系统之前强制初始化程序运行和种子来解决这个问题。
  • 克里斯,我也有类似的问题,但我对 asp .net 真的很陌生。你能告诉他如何强制初始化程序在会员系统之前运行吗?谢谢
  • 看看这个其他类似问题的答案stackoverflow.com/q/7004701/247328

标签: sql entity-framework code-first ef-code-first


【解决方案1】:

简单地关闭我的整个项目并重新打开它对我有用。这是确保没有连接仍然打开的最简单方法

【讨论】:

    【解决方案2】:

    我在 EF 6 中发现这失败并出现 ALTER DATABASE statement not allowed within multi-statement transaction 错误。

    解决方案是像这样使用新的事务行为重载:

    context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
    

    【讨论】:

    • 很棒的评论。修复了我在将 ALTER DATABASE 发布为 SET ALLOW_SNAPSHOT_ISOLATION ON 时创建 EF 6 代码优先数据库的问题。谢谢!
    • 喜欢 SO,因为它找到了像这样的节省时间的小宝石……感谢分享!
    • 在重新创建后将 DB 切换回多用户模式也很有意义,例如: context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.数据库 + "] SET MULTI_USER WITH ROLLBACK IMMEDIATE");
    • 这对我来说非常方便。只是在我的 context.Database.Delete() 调用之前删除了一行,它解决了我的问题。
    【解决方案3】:

    我意识到这已经过时了,但我无法让公认的解决方案发挥作用,所以我推出了一个快速解决方案......

    using System;
    using System.Data.Entity;
    
    namespace YourCompany.EntityFramework
    {
        public class DropDatabaseInitializer<T> : IDatabaseInitializer<T> where T : DbContext, new()
        {
            public DropDatabaseInitializer(Action<T> seed = null)
            {
                Seed = seed ?? delegate {};
            }
    
            public Action<T> Seed { get; set; }
    
            public void InitializeDatabase(T context)
            {
                if (context.Database.Exists())
                {
                    context.Database.ExecuteSqlCommand("ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
                    context.Database.ExecuteSqlCommand("USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
                }
    
                context.Database.Create();
    
                Seed(context);
            }
        }
    }
    

    这对我有用,并且很容易支持播种。

    【讨论】:

    • 这个错误对我来说是因为它说数据库已经使用 VS2012 存在
    • 您在进行身份验证时是否可以访问 master?这对 USE master DROP DATABASE 至关重要
    • @DaveJellison 我尝试了您的解决方案,但它给了我 System.Data.SqlClient.SqlException :多语句事务中不允许 ALTER DATABASE 语句。有什么想法吗?
    • 实际上,您应该将数据库名称变量括在括号中,如context.Database.ExecuteSqlCommand("ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE"); 否则,我收到一个错误,抱怨 WITH 关键字。
    • @ashutoshrina 尝试将 TransactionalBehavior.DoNotEnsureTransaction 参数添加到 ExecuteSqlCommand 方法。更多信息:stackoverflow.com/questions/21699075/…
    【解决方案4】:

    在 Visual Studio 2012 中,SQL Server 对象资源管理器 窗口可以保持与数据库的连接。关闭窗口和从它打开的所有窗口都会释放连接。

    【讨论】:

      【解决方案5】:

      您当前的上下文必须有一个打开的连接才能删除数据库。问题是可能有其他打开的连接会阻止您的数据库初始化程序。一个很好的例子是在 Management Studio 中打开数据库中的任何表。另一个可能的问题是应用程序的连接池中打开的连接。

      在 MS SQL 中,可以通过将 DB 切换到 SINGLE USER 模式并强制关闭所有连接并回滚不完整的事务来避免这种情况:

      ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE
      

      您可以创建一个新的初始化程序,它将首先调用此命令然后删除数据库。请注意,您应该自己处理数据库连接,因为必须在同一连接上调用 ALTER DATABASEDROP DATABASE

      编辑:

      这里有使用装饰器模式的示例。您可以修改它并在构造函数中初始化内部初始化程序,而不是将其作为参数传递。

      public class ForceDeleteInitializer : IDatabaseInitializer<Context>
      {
          private readonly IDatabaseInitializer<Context> _initializer;
      
          public ForceDeleteInitializer(IDatabaseInitializer<Context> innerInitializer)
          {
              _initializer = innerInitializer;    
          }
      
          public void InitializeDatabase(Context context)
          {
              context.Database.SqlCommand("ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
              _initializer.InitializeDatabase(context);
          }
      }
      

      【讨论】:

      • 我没有在 DB 上打开 SSMS 连接,但我的问题是 Initializer 没有提供适当的挂钩来执行您推荐的代码,更不用说我不应该做框架内务。跨度>
      • 它提供了钩子——你可以实现自定义IDatabaseInitializer,你可以在context.Database.SetInitializer()注册。
      • 啊,是的,其实我不久前就发现了,现在正在尝试。
      • 现在我的问题是如何根据模型重新创建数据库。通过使用更通用的 IDatabaseInitializer,我失去了它,必须自己实现它。
      • 这个答案没问题。但播种似乎效果不佳。此外,如果您将所需的初始化策略子类化,则不需要 innerInitializer 的东西。
      【解决方案6】:

      我遇到了同样的问题。

      我通过关闭在 Visual Studio 的服务器资源管理器视图下打开的连接解决了这个问题。

      【讨论】:

      • 从没想过看那里。呃。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 2014-03-07
      • 2011-08-05
      • 2016-08-22
      相关资源
      最近更新 更多