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)
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)
这对我有用,并且很容易支持播种.