20

Sto provando a creare un nuovo database utilizzando il primo concetto di codice di Entity Framework. Tuttavia, quando si esegue il codice, il database non viene creato (utilizzando l'impostazione DropCreateDatabaseIfModelChanges), sebbene il codice funzioni correttamente. Vedo la seguente eccezione quando cerco di ottenere qualcosa dal database.Entity Framework 5 code-first non crea il database

enter image description here

Il mio progetto è di installazione utilizzando un DataAccess livello separato con un servizio generico e la costruzione repository. Quindi tutte le mie entità, repository e anche il contesto del database sono in un progetto separato all'interno della soluzione.

Il file global.asax contiene il seguente codice.

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

Questo dovrebbe inizializzare un nuovo database se non è lì, giusto?

La classe di contesto del database è simile alla seguente;

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

Ho creato questa classe seguendo diversi tutorial e articoli su Internet. È tutto nuovo per me, ma per quanto posso vedere tutto sembra corretto finora. Quindi ora le due entità che sto usando. Si chiamano "Progetto" e "Portafoglio". Sembrano così;

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

E

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

Il database che sto utilizzando è in esecuzione su un server esterno, è venuto con il fornitore di hosting che sto utilizzando. Ho un database SQL Server attivo e funzionante e la stringa di connessione al database si trova nello web.config del progetto del sito web. Ho già provato a rimuovere il database e lasciare che il codice lo ricrei, che purtroppo non ha funzionato. Mi sto perdendo qualcosa di ovvio qui? O potrebbe essere una cosa semplice come diritti di accesso al server per creare database?

Nota: quando eseguo il comando Database-Update -Script per generare il codice SQL, sembra che vengano create le istruzioni SQL corrette per creare tutte le tabelle.

UPDATE 1: OK, grazie ad alcuni commenti sono arrivato un po 'oltre. Ho aggiunto due proprietà alle mie entità per forzare alcune modifiche e ho anche creato un inizializzatore personalizzato come questo;

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

Ho anche rimosso l'inizializzazione dal costruttore del mio contesto, quindi questo significa che ho rimuovere questa riga di codice;

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

Dopo che ho aggiunto queste tre linee al mio Global.file asax;

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

In fase di debug ora sto ricevendo questa eccezione; enter image description here

questo mi dà le seguenti informazioni:

  • InnerException dice: Il provider non ha restituito un ProviderManifestToken
  • InnerException nel InnerException dice: "Per questa operazione una connessione alla masterdatabase è richiesto.Una connessione non può essere larghezza fatta il 'master'-database perché la connessione originale è aperto e i riferimenti sono stati rimossi dalla connessione Si prega di fornire una connessione non aperta"

Dopo queste azioni il database è inaccessibile, quindi molto probabilmente cancellato ..

Cosa può eventualmente essere fatto su questo? È molto probabile che non riesca ad accedere al database master perché il mio hostingprovider non mi darà il diritto di accesso corretto per il corso.

+0

Il codice e la configurazione sembrano OK, probabilmente sei bloccato sulla situazione di hosting. EF vuole creare il tuo Db con una speciale tabella di supporto (1 o 2 hash). Forse puoi copiarlo da un Db locale e spostarlo nel Db ospitato? –

+0

L'account utente che esegue il codice ha le autorizzazioni necessarie per eliminare e creare database? – jlew

+0

@Henk, ho appena provato a eseguire lo script SQL generato. Ha creato per me un tavolo __MigrationHistory con un record. Ho anche modificato il costruttore del mio contesto aggiungendo la riga 'this.Database.Initialize (true)'. Questo non mi ha dato un errore, ma non ho creato alcun tavolo. Ho quindi eliminato il record dalla tabella MigrationHistory e ho avuto di nuovo lo stesso errore. Quindi cercherò di eseguirlo su un database locale ora e vedere cosa succede. – Rob

risposta

12

Dal momento che nessun altra soluzione è venuto da ho deciso di cambiare il mio approccio.

Ho creato il database personalmente e mi sono assicurato che l'utente SQL corretto fosse configurato e che avessi accesso.

Quindi ho rimosso l'inizializzatore e il codice dal file Global.asax. Successivamente ho eseguito il seguente comando nella console di Gestione pacchetti (dal momento che il design a strati dovevo selezionare il progetto corretto nella console);

Enable-Migrations 

Dopo le migrazioni dove abilitati e ho fatto alcune modifiche dell'ultimo minuto ai miei entità Ho eseguito il seguente comando per patibolo una migrazione nuova;

Add-Migration AddSortOrder 

Dopo la creazione delle migrazioni, ho eseguito il comando seguente nella console e voilà, il database è stato aggiornato con le mie entità;

Update-Database -Verbose 

Per essere in grado di seminare il database durante l'esecuzione della migrazione ho sovrascritto il metodo del seme nella mia classe Configuraton.cs, che è stato creato quando si abilita le migrazioni. Il codice finale in questo metodo è come questo;

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

Lo svantaggio al momento è che devo migrare manualmente con (solo) 2 comandi nella console gestore di pacchetti. Ma allo stesso tempo, il fatto che questo non avvenga in modo dinamico è anche un bene perché questo impedisce possibili modifiche indesiderate al mio database. Inoltre tutto funziona perfettamente.

1

+1 per la domanda dettagliata.

Verificare che la stringa di connessione è puntato verso il database corretto e aggiungere l'autorizzazione attribuisce come questo per accedere al database:

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

befor intialize correre seguente codice per creare il database:

context.Database.CreateIfNotExists();

Problemi correlati