Entity Framework 4 Code First 出现数据库使用错误

发布于 2024-10-22 06:00:40 字数 514 浏览 3 评论 0原文

我有一个 MVC3 和 EF 4 Code First 应用程序,该应用程序配置为在模型更改时更改数据库,方法是将数据库初始化程序设置为 DropCreateDatabaseIfModelChanges,其中 TocratesDb 是我派生的DbContext

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

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

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

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

I have an MVC3 and EF 4 Code First application, which is configured to change the DB when the model changes, by setting the DB Initializer to a DropCreateDatabaseIfModelChanges<TocratesDb>, where TocratesDb is my derived DbContext.

I have now made a change to the model, by adding properties to a class, but when EF tries to drop and recreate the DB, I get the following error:

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

I have absolutely no other connections anywhere open on this database. I assume that my cDbContext still has an open connection to the database, but what can I do about this?

NEW: Now my problem is how to re-create the database based on the model. By using the more general IDatabaseInitializer, I lose that and have to implement it myself.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦里兽 2024-10-29 06:00:40

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

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

ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE

您可以创建一个新的初始化程序,它将首先调用此命令,然后删除数据库。请注意,您应该自己处理数据库连接,因为必须在同一连接上调用 ALTER DATABASE 和 DROP 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);
    }
}

Your current context must have an opened connection to be able to drop the database. The problem is that there can be other opened connections which will block your db initializer. One very nice example is having opened any table from your database in management studio. Another possible problem can be opened connections in the connection pool of your application.

In MS SQL this can be avoided for example by switching DB to SINGLE USER mode and forcing all connections to be closed and incomplete transactions rolled back:

ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE

You can create a new intializer which will first call this command and then drops the database. Be aware that you should handle a database connection by yourselves because ALTER DATABASE and DROP DATABASE must be called on the same connection.

Edit:

Here you have example using Decorator pattern. You can modify it and initialize inner initializer inside the constructor instead of passing it as a parameter.

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);
    }
}
人生戏 2024-10-29 06:00:40

我发现在 EF 6 中,此操作会失败,并出现 ALTER DATABASE statements not allowed inside multi-statement transaction 错误。

解决方案是使用新的事务行为重载,如下所示:

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

I found in EF 6 this fails with an ALTER DATABASE statement not allowed within multi-statement transaction error.

The solution was to use the new transaction behavior overload like this:

context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
初吻给了烟 2024-10-29 06:00:40

我有同样的问题。

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

I had the same issue.

I resolved it by closing a connection open under the Server Explorer view of Visual Studio.

葬花如无物 2024-10-29 06:00:40

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

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);
        }
    }
}

这对我有用,并且可以轻松支持播种。

I realize this is dated but I couldn't get the accepted solution working so I rolled a quick solution...

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);
        }
    }
}

This works for me and supports seeding easily.

岁月染过的梦 2024-10-29 06:00:40

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

In Visual Studio 2012, the SQL Server Object Explorer window can hold a connection to the database. Closing the window and all windows opened from it releases the connection.

另类 2024-10-29 06:00:40

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

A simple closing of my whole project and reopening it did the trick for me. It's the easiest way to make sure there are no connections still open

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文