正在使用的数据库错误与实体框架4代码优先

Pro*_*ofK 51 sql entity-framework code-first ef-code-first

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

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

Cannot drop database "Tocrates" because it is currently in use.
Run Code Online (Sandbox Code Playgroud)

我绝对没有在这个数据库上打开任何其他连接.我假设我的cDbContext仍然与数据库有一个开放的连接,但我该怎么办呢?

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

Lad*_*nka 46

您当前的上下文必须具有已打开的连接才能删除数据库.问题是可能有其他打开的连接将阻止您的db初始化程序.一个非常好的例子是在管理工作室中打开数据库中的任何表.另一个可能的问题是可以在应用程序的连接池中打开连接.

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

ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE
Run Code Online (Sandbox Code Playgroud)

您可以创建一个新的初始化程序,它将首先调用此命令,然后删除数据库.要知道,你应该处理你们自己,因为一个数据库连接ALTER DATABASE,并DROP DATABASE必须在同一个连接上调用.

编辑:

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Kev*_*zyk 41

我发现在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");
Run Code Online (Sandbox Code Playgroud)

  • 好评.修复了在将ALTER DATABASE发送到SET ALLOW_SNAPSHOT_ISOLATION ON时,EF 6代码首次创建数据库的问题.谢谢! (2认同)

psy*_*psy 21

我遇到过同样的问题.

我通过关闭Visual Studio的Server Explorer视图下打开的连接来解决它.

  • 从来没有想过要看那里.啊. (3认同)

Dav*_*son 13

我意识到这已经过时了,但我无法使用已接受的解决方案,所以我推出了快速解决方案......

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • @DaveJellison我尝试了你的解决方案,但它给了我System.Data.SqlClient.SqlException:多语句事务中不允许ALTER DATABASE语句.有任何想法吗 ? (4认同)