ventajas tutorial framework first español code sql entity-framework code-first ef-code-first

sql - tutorial - model first



Error en la base de datos en uso con el código de Entity Framework 4 (6)

Tengo una aplicación MVC3 y EF 4 Code First, que está configurada para cambiar la base de datos cuando cambia el modelo, estableciendo el inicializador de base de datos en DropCreateDatabaseIfModelChanges<TocratesDb> , donde TocratesDb es mi DbContext derivado.

Ahora he realizado un cambio en el modelo, agregando propiedades a una clase, pero cuando EF intenta descartar y volver a crear la base de datos, aparece el siguiente error:

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

No tengo absolutamente ninguna otra conexión abierta en esta base de datos. Supongo que mi cDbContext todavía tiene una conexión abierta a la base de datos, pero ¿qué puedo hacer al respecto?

NUEVO: Ahora mi problema es cómo volver a crear la base de datos según el modelo. Al usar el IDatabaseInitializer más general, lo pierdo y tengo que implementarlo yo mismo.


En Visual Studio 2012, la ventana del Explorador de objetos del servidor SQL puede contener una conexión a la base de datos. Al cerrar la ventana y todas las ventanas abiertas se libera la conexión.


Encontré en EF 6 que esto falla con una ALTER DATABASE statement not allowed within multi-statement transaction error de ALTER DATABASE statement not allowed within multi-statement transaction .

La solución fue usar la nueva sobrecarga de comportamiento de transacción como esta:

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


Me doy cuenta de que esto está pasado de moda, pero no pude lograr que funcionara la solución aceptada, así que lancé una solución rápida ...

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

Esto funciona para mí y ayuda a sembrar fácilmente.


Su contexto actual debe tener una conexión abierta para poder soltar la base de datos. El problema es que puede haber otras conexiones abiertas que bloquearán su inicializador db. Un buen ejemplo es haber abierto cualquier tabla desde su base de datos en el estudio de administración. Otro posible problema pueden ser las conexiones abiertas en el grupo de conexiones de su aplicación.

En MS SQL, esto se puede evitar, por ejemplo, cambiando el DB al modo SINGLE USER y forzando que todas las conexiones se cierren y las transacciones incompletas se reviertan:

ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE

Puede crear un intializador nuevo que primero llame a este comando y luego descarte la base de datos. Tenga en cuenta que debe manejar una conexión de base de datos por sí mismo porque debe ALTER DATABASE y DROP DATABASE en la misma conexión.

Editar:

Aquí tienes un ejemplo usando el patrón Decorator. Puede modificarlo e inicializar el inicializador interno dentro del constructor en lugar de pasarlo como un parámetro.

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


Tuve el mismo problema.

Lo resolví cerrando una conexión abierta bajo la vista Server Explorer de Visual Studio.


Un simple cierre de todo mi proyecto y su reapertura me funcionó. Es la forma más fácil de asegurarse de que todavía no hay conexiones abiertas