SQL Entity Framework 4 Code First 的数据库使用错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5288996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 09:41:07  来源:igfitidea点击:

Database in use error with Entity Framework 4 Code First

sqlentity-frameworkcode-firstef-code-first

提问by ProfK

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 TocratesDbis my derived DbContext.

我有一个 MVC3 和 EF 4 Code First 应用程序,它被配置为在模型更改时更改数据库,方法是将 DB Initializer 设置为 a DropCreateDatabaseIfModelChanges<TocratesDb>TocratesDb我派生的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:

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

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?

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

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.

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

采纳答案by Ladislav Mrnka

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.

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

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:

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

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 DATABASEand DROP DATABASEmust be called on the same connection.

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

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

回答by Kevin Kuszyk

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

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

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

回答by psy

I had the same issue.

我遇到过同样的问题。

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

我通过关闭在 Visual Studio 的服务器资源管理器视图下打开的连接来解决它。

回答by Dave Jellison

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.

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

回答by Edward Brey

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

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

回答by user6302183

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

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