数据库使用错误与entity framework4代码第一
我有一个MVC3和EF 4 Code First应用程序,通过将DB初始化程序设置为DropCreateDatabaseIfModelChanges<TocratesDb>
(其中TocratesDb
是我的派生DbContext
,将其configuration为在模型更改时更改数据库。
我现在通过向类添加属性来对模型进行更改,但是当EF尝试删除并重新创build数据库时,出现以下错误:
Cannot drop database "Tocrates" because it is currently in use.
我在这个数据库上的任何地方都没有其他连接。 我假设我的cDbContext仍然有一个开放的连接到数据库,但我能做些什么呢?
新:现在我的问题是如何基于模型重新创build数据库。 通过使用更一般的IDatabaseInitializer,我失去了这一点,必须自己实现它。
您当前的上下文必须有一个打开的连接才能删除数据库。 问题是可能有其他打开的连接会阻止你的数据库初始值设定项。 一个非常好的例子是在pipe理工作室中从数据库中打开任何表格。 另一个可能的问题是可以在应用程序的连接池中打开连接。
在MS SQL中,可以避免这种情况,例如将DB切换到单用户模式,并强制closures所有连接,并将不完整的事务回滚:
ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE
你可以创build一个新的初始化器,它将首先调用这个命令,然后删除数据库。 请注意,您应该自己处理数据库连接,因为必须在同一个连接上调用ALTER DATABASE
和DROP DATABASE
。
编辑:
在这里你有使用装饰模式的例子。 您可以在构造函数中修改它并初始化内部初始值设定项,而不是将其作为parameter passing。
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); } }
我在EF 6中发现,这个失败, ALTER DATABASE statement not allowed within multi-statement transaction
错误中ALTER DATABASE statement not allowed within multi-statement transaction
使用ALTER DATABASE statement not allowed within multi-statement transaction
。
解决scheme是使用新的事务行为过载如下:
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
我遇到过同样的问题。
我通过closures在Visual Studio的“服务器资源pipe理器”视图下打开的连接来解决此问题。
我意识到这是过时的,但我不能得到公认的解决scheme工作,所以我推出了一个快速解决scheme…
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); } } }
这对我有用,并支持轻松播种。
在Visual Studio 2012中, SQL Server对象资源pipe理器窗口可以保存到数据库的连接。 closures窗口及其打开的所有窗口将释放连接。
一个简单的closures我的整个项目,并重新打开它为我做了诡计。 这是确保没有连接仍然打开的最简单的方法