wake-up-neo.com

Beim Entity Framework 5-Code-First wird keine Datenbank erstellt

Ich versuche, eine neue Datenbank mit dem Code-First-Konzept von Entity Framework zu erstellen. Beim Ausführen des Codes wird die Datenbank jedoch nicht erstellt (mit der Einstellung DropCreateDatabaseIfModelChanges), obwohl der Code einwandfrei ausgeführt wird. Ich sehe die folgende Ausnahme, wenn ich versuche, etwas aus der Datenbank zu bekommen.

enter image description here

Mein Projekt wird mit einer separaten DataAccess-Ebene mit einem generischen Service und Repository-Aufbau eingerichtet. Alle meine Entitäten, das Repository und auch der Datenbankkontext befinden sich also in einem separaten Projekt innerhalb der Lösung.

Meine global.asax-Datei enthält den folgenden Code.

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

Dies sollte eine neue Datenbank initialisieren, wenn sie nicht vorhanden ist, oder?

Meine Datenbankkontextklasse sieht so aus;

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

Ich habe diese Klasse nach mehreren Tutorials und Artikeln im Internet erstellt. Es ist alles neu für mich, aber soweit ich sehen kann, scheint alles soweit richtig. Also jetzt die zwei Entitäten, die ich verwende. Sie heißen "Projekt" und "Portfolio". Sie sehen so aus;

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

Und

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

Die Datenbank, die ich verwende, läuft auf einem externen Server, sie wurde mit dem Hosting-Provider geliefert, den ich verwende. Ich habe eine SQL Server-Datenbank installiert und die Verbindungszeichenfolge zur Datenbank befindet sich im web.config des Website-Projekts. Ich habe bereits versucht, die Datenbank zu entfernen und den Code neu erstellen zu lassen, was leider nicht funktioniert hat. Fehlt mir hier etwas offensichtliches? Oder könnte es eine einfache Sache sein, als Zugriffsrechte auf den Server, um Datenbanken zu erstellen?

Hinweis: Wenn ich den Befehl Database-Update -Script zum Generieren von SQL-Code ausführen, scheinen die richtigen SQL-Anweisungen zum Erstellen aller Tabellen erstellt zu sein.

UPDATE 1: Okay, dank einiger Kommentare bin ich etwas weiter gekommen. Ich habe meinen Entitäten zwei Eigenschaften hinzugefügt, um einige Änderungen zu erzwingen, und ich habe auch einen benutzerdefinierten Initialisierer wie diesen erstellt.

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

Ich habe auch den Initialisierer aus dem Konstruktor meines Kontextes entfernt. Dies bedeutet, dass ich diese Codezeile entfernt habe.

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

Danach habe ich diese drei Zeilen meiner Global.asax-Datei hinzugefügt.

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

Beim Debuggen bekomme ich jetzt diese Ausnahme; enter image description here

Dies gibt mir folgende Informationen:

  • InnerException besagt: Der Provider hat kein ProviderManifestToken zurückgegeben
  • InnerException in der InnerException sagt: "Für diesen Vorgang ist eine Verbindung zur Stammdatenbank erforderlich. Eine Verbindung kann nicht mit der 'master'-Datenbank erstellt werden, da die ursprüngliche Verbindung geöffnet ist und die Referenzen entfernt wurden von der Verbindung . Bitte geben Sie eine nicht offene Verbindung an. "

Nach diesen Aktionen ist auf die Datenbank nicht mehr zugegriffen, daher höchstwahrscheinlich gelöscht.

Was kann man dagegen tun? Es ist sehr wahrscheinlich, dass ich nicht auf die Master-Datenbank zugreifen kann, da mein Hosting-Provider mir nicht das richtige Zugriffsrecht gibt.

20
Rob

Da keine andere Lösung kam, entschied ich mich, meine Herangehensweise zu ändern.

Ich habe die Datenbank zuerst selbst erstellt und sichergestellt, dass der richtige SQL-Benutzer konfiguriert wurde und ich Zugriff hatte.

Dann entfernte ich den Initialisierer und den Code aus der Datei Global.asax. Danach habe ich den folgenden Befehl in der Package Manager Console ausgeführt (seit dem mehrstufigen Design musste ich das richtige Projekt in der Konsole auswählen);

Enable-Migrations

Nachdem die Migrationen aktiviert waren und ich letzte Änderungen an meinen Entitäten vorgenommen hatte, führte ich den folgenden Befehl aus, um eine neue Migration zu erstellen.

Add-Migration AddSortOrder

Nachdem meine Migrationen erstellt wurden, habe ich den folgenden Befehl in der Konsole ausgeführt und voila, die Datenbank wurde mit meinen Entitäten aktualisiert.

Update-Database -Verbose

Um die Datenbank bei der Ausführung der Migration als Seeding verwenden zu können, habe ich die Methode Seed in meiner Configuraton.cs-Klasse überschrieben, die beim Aktivieren der Migrationen erstellt wurde. Der endgültige Code in dieser Methode ist wie folgt;

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

Der Nachteil ist im Moment, dass ich manuell mit (nur) 2 Befehlen in der Paket-Manager-Konsole migrieren muss. Gleichzeitig ist die Tatsache, dass dies nicht dynamisch geschieht, auch gut, weil dadurch möglicherweise unerwünschte Änderungen an meiner Datenbank verhindert werden. Weiterhin funktioniert alles einfach perfekt.

13
Rob

+1 für die detaillierte Frage.

Stellen Sie sicher, dass Ihre Verbindungszeichenfolge auf die richtige Datenbank zeigt, und fügen Sie die Berechtigungsattribute wie folgt hinzu, um auf Ihre Datenbank zuzugreifen:

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

führen Sie vor dem Initialisieren folgenden Code aus, um Ihre Datenbank zu erstellen:

context.Database.CreateIfNotExists ();

0
Mohammad Ansari

Entfernen Sie daher zuerst den Datenbanknamen aus dem Parameter "Konstruktor" für die Kontextklasse und geben Sie "Db_name" für die Verbindungszeichenfolge ein. Versuchen Sie anschließend, Ihre Lösung neu zu erstellen und die Anwendung auszuführen, die die Datenbank für Ihre Anwendung erstellt.

Zum Beispiel :

Ich übergebe den DB-Namen nicht an den Konstruktor-Parameter 

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

und auf der Verbindungszeichenfolge gebe ich den Db-Namen wie folgt weiter.

    <add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;[email protected];persistsecurityinfo=True" providerName="System.Data.SqlClient"/>
  </connectionStrings> 
0
Sharad Tiwari