mvc migrations framework first existing espaƱol code c# entity-framework asp.net-mvc-4 ef-code-first entity-framework-5

c# - migrations - Entity Framework 5 code-first no crea base de datos



entity framework model first (4)

+1 para la pregunta detallada.

Compruebe que su cadena de conexión apunta a la base de datos correcta y agregue los atributos de autorización como este para acceder a su base de datos:

<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />

Estoy tratando de crear una nueva base de datos usando el primer concepto de código de Entity Framework. Sin embargo, cuando se ejecuta el código, la base de datos no se crea (utilizando la configuración DropCreateDatabaseIfModelChanges ), aunque el código funciona bien. Estoy viendo la siguiente excepción cuando trato de obtener algo de la base de datos.

Mi proyecto se configura utilizando una capa de DataAccess separada con un servicio genérico y una construcción de repositorio. Por lo tanto, todas mis entidades, el repositorio y también el contexto de la base de datos están en un proyecto separado dentro de la solución.

Mi archivo global.asax contiene el siguiente fragmento de código.

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());

Esto debería inicializar una nueva base de datos si no está allí, ¿verdad?

Mi clase de contexto de base de datos se ve así;

namespace Website.DAL.Model { public class MyContext : DbContext { public IDbSet<Project> Projects { get; set; } public IDbSet<Portfolio> Portfolios { get; set; } /// <summary> /// The constructor, we provide the connectionstring to be used to it''s base class. /// </summary> public MyContext() : base("MyConnectionString") { } static MyContext() { try { Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>()); } catch (Exception) { throw; } } /// <summary> /// This method prevents the plurarization of table names /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>(); } } }

He creado esta clase siguiendo varios tutoriales y artículos en internet. Todo es nuevo para mí, pero hasta donde puedo ver, todo parece correcto hasta ahora. Así que ahora las dos entidades que estoy usando. Se llaman ''Proyecto'' y ''Cartera''. Se ven así;

public class Portfolio { [Key] public Guid Id { get; set; } public String Name { get; set; } public DateTime StartDate { get; set; } public DateTime? EndDate { get; set; } public bool IsPublished { get; set; } public virtual ICollection<Project> Projects { get; set; } }

Y

public class Project { [Key] public Guid Id { get; set; } public DateTime StartDate { get; set; } public DateTime? EndDate { get; set; } public bool IsPublished { get; set; } public String Title { get; set; } }

La base de datos que estoy usando se está ejecutando en un servidor externo, vino con el proveedor de alojamiento que estoy usando. Tengo una base de datos de SQL Server en funcionamiento y la cadena de conexión a la base de datos se encuentra en web.config del proyecto del sitio web. Ya intenté eliminar la base de datos y dejé que el código la volviera a crear, lo que desafortunadamente no funcionó. ¿Me estoy perdiendo algo obvio aquí? ¿O podría ser algo simple como derechos de acceso al servidor para crear bases de datos?

Nota: Cuando ejecuto el comando Database-Update -Script para generar código SQL, parece que se crean las sentencias SQL correctas para crear todas las tablas.

ACTUALIZACIÓN 1: Bueno, gracias a algunos comentarios he venido un poco más lejos. He agregado dos propiedades a mis entidades para forzar algunos cambios y también he creado un inicializador personalizado como este;

public class ForceDeleteInitializer : IDatabaseInitializer<MyContext> { private readonly IDatabaseInitializer<MyContext> _initializer = new DropCreateDatabaseIfModelChanges<MyContext>(); public ForceDeleteInitializer() { //_initializer = new ForceDeleteInitializer(); } public void InitializeDatabase(MyContext context) { //This command is added to prevent open connections. See http://stackoverflow.com/questions/5288996/database-in-use-error-with-entity-framework-4-code-first context.Database.ExecuteSqlCommand("ALTER DATABASE borloOntwikkel SET SINGLE_USER WITH ROLLBACK IMMEDIATE"); _initializer.InitializeDatabase(context); } }

También he eliminado el inicializador del constructor de mi contexto, por lo que esto significa que he eliminado esta línea de código;

Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());

Después de eso, he agregado estas tres líneas a mi archivo Global.asax;

Database.SetInitializer(new ForceDeleteInitializer()); MyContext c = new MyContext(); c.Database.Initialize(true);

Al depurar ahora estoy obteniendo esta excepción;

Esto me da la siguiente información:

  • InnerException dice: el proveedor no devolvió un ProviderManifestToken
  • La InnerException en la InnerException dice: "Para esta operación se requiere una conexión a la base de datos maestra. No se puede establecer una conexión con la base de datos ''maestra'' porque la conexión original se abrió y las referencias se eliminaron de la conexión. Proporcione una conexión no abierta "

Después de estas acciones, la base de datos es inaccesible, por lo que es muy probable que se elimine.

¿Qué se puede hacer al respecto? Es muy probable que no pueda acceder a la base de datos maestra porque mi proveedor de alojamiento no me da el derecho de acceso adecuado por supuesto.


Antes de iniciarlo, ejecute el siguiente código para crear su base de datos:

context.Database.CreateIfNotExists ();


Como no surgió ninguna otra solución, decidí cambiar mi enfoque.

Primero creé la base de datos y me aseguré de que el usuario de SQL correcto estuviera configurado y de que tuviera acceso.

Luego eliminé el inicializador y el código del archivo Global.asax. Después de eso ejecuté el siguiente comando en la Consola del administrador de paquetes (ya que el diseño en capas tuve que seleccionar el proyecto correcto en la consola);

Enable-Migrations

Después de que las migraciones estuvieran habilitadas y realicé algunos cambios de último minuto en mis entidades, ejecuté el siguiente comando para crear una nueva migración;

Add-Migration AddSortOrder

Después de que se crearon mis migraciones, ejecuté el siguiente comando en la consola y, voila, la base de datos se actualizó con mis entidades;

Update-Database -Verbose

Para poder sembrar la base de datos al ejecutar la migración, he anulado el método Seed en mi clase Configuraton.cs, que se creó al habilitar las migraciones. El código final en este método es así;

protected override void Seed(MyContext context) { // This method will be called after migrating to the latest version. //Add menu items and pages if (!context.Menu.Any() && !context.Page.Any()) { context.Menu.AddOrUpdate(new Menu() { Id = Guid.NewGuid(), Name = "MainMenu", Description = "Some menu", IsDeleted = false, IsPublished = true, PublishStart = DateTime.Now, LastModified = DateTime.Now, PublishEnd = null, MenuItems = new List<MenuItem>() { new MenuItem() { Id = Guid.NewGuid(), IsDeleted = false, IsPublished = true, PublishStart = DateTime.Now, LastModified = DateTime.Now, PublishEnd = null, Name = "Some menuitem", Page = new Page() { Id = Guid.NewGuid(), ActionName = "Some Action", ControllerName = "SomeController", IsPublished = true, IsDeleted = false, PublishStart = DateTime.Now, LastModified = DateTime.Now, PublishEnd = null, Title = "Some Page" } }, new MenuItem() { Id = Guid.NewGuid(), IsDeleted = false, IsPublished = true, PublishStart = DateTime.Now, LastModified = DateTime.Now, PublishEnd = null, Name = "Some MenuItem", Page = new Page() { Id = Guid.NewGuid(), ActionName = "Some Action", ControllerName = "SomeController", IsPublished = true, IsDeleted = false, PublishStart = DateTime.Now, LastModified = DateTime.Now, PublishEnd = null, Title = "Some Page" } } } }); } if (!context.ComponentType.Any()) { context.ComponentType.AddOrUpdate(new ComponentType() { Id = Guid.NewGuid(), IsDeleted = false, IsPublished = true, LastModified = DateTime.Now, Name = "MyComponent", PublishEnd = null, PublishStart = DateTime.Now }); } try { // Your code... // Could also be before try if you know the exception occurs in SaveChanges context.SaveChanges(); } catch (DbEntityValidationException e) { //foreach (var eve in e.EntityValidationErrors) //{ // Console.WriteLine("Entity of type /"{0}/" in state /"{1}/" has the following validation errors:", // eve.Entry.Entity.GetType().Name, eve.Entry.State); // foreach (var ve in eve.ValidationErrors) // { // Console.WriteLine("- Property: /"{0}/", Error: /"{1}/"", // ve.PropertyName, ve.ErrorMessage); // } //} //throw; var outputLines = new List<string>(); foreach (var eve in e.EntityValidationErrors) { outputLines.Add(string.Format( "{0}: Entity of type /"{1}/" in state /"{2}/" has the following validation errors:", DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State)); foreach (var ve in eve.ValidationErrors) { outputLines.Add(string.Format( "- Property: /"{0}/", Error: /"{1}/"", ve.PropertyName, ve.ErrorMessage)); } } System.IO.File.AppendAllLines(@"c:/temp/errors.txt", outputLines); throw; } }

La desventaja en este momento es que tengo que migrar manualmente con (solo) 2 comandos en la consola del administrador de paquetes. Pero al mismo tiempo, el hecho de que esto no ocurra dinámicamente también es bueno porque evita posibles cambios no deseados en mi base de datos. Además todo funciona simplemente perfecto.


Entonces, primero elimine el nombre Db del parámetro constructor en la clase de contexto y proporcione D_n_name en la cadena de conexión y luego intente reconstruir su solución y ejecutar la aplicación que creará la base de datos para su aplicación.

Por ejemplo :

No estoy pasando el nombre Db en el parámetro constructor

public EmployeeContext() : base() { Database.SetInitializer<EmployeeContext>(new DropCreateDatabaseIfModelChanges<EmployeeContext>()); }

y en la cadena de conexión paso el nombre Db como se muestra abajo.

<add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;Password=crius@123;persistsecurityinfo=True" providerName="System.Data.SqlClient"/> </connectionStrings>