webentwicklung-frage-antwort-db.com.de

Wie kann ich meine Datenbank mit Entity Framework Code First zum Start bringen?

Die Datenbank wird erfolgreich erstellt (wie auch die Tabellen), aber nicht geimpft. Ich habe mehrere Stunden damit verbracht, Tonnen von Artikeln zu lesen, konnte sie aber nicht bekommen. Irgendwelche Vorschläge?

Kann der Initialisierer auch ohne einen Verweis auf meinen DatabaseContext im Client aufgerufen werden?

Ich habe alle relevanten Codes eingefügt, die mir einfallen. Wenn noch etwas hilfreich wäre, lassen Sie es mich bitte wissen.

Dinge, die ich ausprobiert habe:

  1. Ich habe meine Verbindungszeichenfolge gelöscht (da es sowieso standardmäßig sqlexpress ist, hat sich nur der Name geändert)
  2. Ich habe DropCreateDatabaseIfModelChanges in DropCreateDatabaseAlways geändert, immer noch dasselbe.

Edit: Das wirklich seltsame ist, dass es einmal funktioniert hat, aber ich habe keine Ahnung, wie oder warum es wieder kaputt gegangen ist. Ich gehe von Verbindungszeichenfolgen aus, aber wer weiß.

DatabaseInitializer.cs

public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext>
{
  protected override void Seed(DatabaseContext context)
  {
    // Seeding data here
    context.SaveChanges();
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder mb)
  {
    // Random mapping code
  }

  public DbSet<Entity1> Entities1 { get; set; }
  public DbSet<Entity2> Entities2 { get; set; }

}

Global.asax.cs - Application_Start ()

protected void Application_Start()
{
  Database.SetInitializer<DatabaseContext>(new DatabaseInitializer());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
}

Client web.config

<connectionStrings>
  <add name="DatabaseContext" connectionString="data source=.\SQLEXPRESS;Database=Database;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>

LÖSUNG

Aus Gründen der Dokumentation teile ich meine Lösung hier. In allen Kommentaren zu navigieren wäre sowieso ein Schmerz. Am Ende hatte ich DatabaseInitializer und DatabaseContext in getrennten Klassen. Ich verstehe es nicht wirklich, während diese winzigen Änderungen es reparierten, aber hier ist es.

DatabaseInitializer.cs

public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext>
{
  protected override void Seed(DatabaseContext context)
  {
    // Seed code here
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
  public DatabaseContext() : base("MyDatabase") { }

  protected override void OnModelCreating(DbModelBuilder mb)
  {
    // Code here
  }

  public DbSet<Entity> Entities { get; set; }
  // Other DbSets
}

Global.asax.cs - Application_Start ()

protected void Application_Start()
{
  Database.SetInitializer(new DatabaseInitializer());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
}
62
Alec

So sehen alle meine DbContext-Klassen aus, und sie sind genau richtig:

public class MyDbContext : DbContext
{
    public DbSet<MyClass> MyClasses { get; set; }

    protected override void OnModelCreating (DbModelBuilder modelBuilder)
    {
        base.OnModelCreating (modelBuilder);
        modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention> ();

        // Add any configuration or mapping stuff here
    }

    public void Seed (MyDbContext Context)
    {
        #if DEBUG
        // Create my debug (testing) objects here
        var TestMyClass = new MyClass () { ... };
        Context.MyClasses.Add (TestMyClass);
        #endif

        // Normal seeding goes here

        Context.SaveChanges ();
    }

    public class DropCreateIfChangeInitializer : DropCreateDatabaseIfModelChanges<MyDbContext>
    {
        protected override void Seed (MyDbContext context)
        {
            context.Seed (context);

            base.Seed (context);
        }
    }

    public class CreateInitializer : CreateDatabaseIfNotExists<MyDbContext>
    {
        protected override void Seed (MyDbContext context)
        {
            context.Seed (context);

            base.Seed (context);
        }
    }

    static MyDbContext ()
    {
        #if DEBUG
        Database.SetInitializer<MyDbContext> (new DropCreateIfChangeInitializer ());
        #else
        Database.SetInitializer<MyDbContext> (new CreateInitializer ());
        #endif
    }
}

Ich habe dieses Muster ein paar Mal verwendet und es hat für mich sehr gut geklappt.

37
Jim D'Angelo

Meine Seed -Methode wurde nicht aufgerufen, obwohl Database.SetInitializer im Application_Start... Der Grund dafür war ganz einfach: Der Initialisierer kann möglicherweise überhaupt nicht aufgerufen werden, wenn Sie noch keinen Code haben, der tatsächlich verwendet Datenbankkontext.

10
user1068352

Das ist meine traurige kleine Geschichte.

Erstens, Lektionen gelernt:

  1. Die Seed-Methode wird erst aufgerufen, wenn der Kontext verwendet wird.
  2. Die Datei Global.asax.cs wird beim ersten Ausführen nicht einen Haltepunkt erreichen, bevor der Debugger angehängt wird. Um einen Haltepunkt in Global.asax.cs zu erreichen, können Sie Web.config Leerzeichen hinzufügen und eine Seite aufrufen. dann wird es getroffen.
  3. Wenn VS-Verbindungen zur Datenbank bestehen, wird das Seeding nicht durchgeführt. Die App wird einen Fehler auslösen.

So vermeiden Sie die Traurigkeit:

  • Trennen Sie Ihre VS-Verbindung.
  • Wechseln Sie die Basisklasse DropCreateDatabaseAlways für einen Durchgang.
  • Schlagen Sie eine Seite an, die den Kontext verwendet.

Nun die Traurigkeit:

  1. Ich hatte meine benutzerdefinierte Initialisierungsklasse in meiner Datei Global.asax.cs. Ich hatte einen Haltepunkt auf meiner Initializer Seed Methode; ich habe die Anwendung gestartet und die Methode wurde nie getroffen. :(
  2. Ich zeige in meinem Database.SetInitializer-Aufruf in Application_Start auf einen Haltepunkt. Das wurde nie getroffen. :(
  3. Mir wurde klar, dass ich keine Änderungen am DB-Schema hatte, also habe ich DropCreateDatabaseIfModelChanges in DropCreateDatabaseAlways geändert. Immer noch nichts. :(
  4. Ich ging schließlich zu einer Seite, die den Kontext verwendet, und es hat funktioniert. : /
9
Davious

Du kannst anrufen update-database, um die Startmethode manuell in der Klasse Configuration auszuführen. Dafür braucht man enable-migrations um auch dabei zu sein.

PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending code-based migrations.
Running Seed method.

internal sealed class Configuration : DbMigrationsConfiguration<ProjectManager.Data.Database.ProjectDb>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(ProjectManager.Data.Database.ProjectDb context)
    {
        context.Status.AddOrUpdate(
            new Status() { Id = 1, Text = "New" },
            new Status() { Id = 2, Text = "Working" },
            new Status() { Id = 3, Text = "Completed" },
            new Status() { Id = 4, Text = "Skipped" }
        );
    }
}
3
Despertar

Die folgende Änderung in der Datei Global.asax hat bei mir funktioniert:

Alter Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());             
       ...
    }

Neuer Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }
2
Steven Burton

Auch ich hatte Schwierigkeiten, Seed () aufzurufen. Und ich schätze all die hilfreichen Vorschläge oben und hatte immer etwas Glück mit DropCreateDatabase ... aber nicht IMMER !!

Zuletzt habe ich die folgende Codezeile im Konstruktor meines Repositorys hinzugefügt, um eine gute Wirkung zu erzielen:

    public CatalogRepository()
    {
        _formCatalog.FormDescriptors.GetType();

    }

Es genügte, den Aufruf von Seed () auszulösen. Wenn Sie alles über diese Antwort und noch kein Glück versucht haben, versuchen Sie es. Viel Glück, das war wirklich eine zeitraubende Erfahrung.

1
Joe

Ich hatte das gleiche Problem und nach der Änderung in beiden Global.asax Datei und Intializer Datei hat funktioniert. Ich hoffe, es wird für diejenigen funktionieren, die immer noch Probleme beim Seeding von Daten haben.

Neuer Code in Global.asax:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }

code für die Intializer-Datei:

public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context>
0
mudassir sheikh

Ich bin gerade auf dieses Problem gestoßen. Ich habe den Abschnitt "connectionstrings" aus der Datei "Web.config" gelöscht und momentan wurde die App gestartet - ohne den Abschnitt "connectionstrings"! Ich füge den Abschnitt zurück, und die Datenbank wird nicht erneut gesät. Es ist keine richtige Lösung, aber ich füge hier nur einen Datenpunkt hinzu, um das Problem möglicherweise zu lösen.

Zum Glück ist es nur eine kleine "Wegwerf" -App, die ich sowieso bald verwerfen werde ...

0
Evgeny

Stellen Sie akribisch sicher, dass Sie Ihre Kontextvariable nicht mehr als einmal deklariert haben. Wenn Sie es nach der Aussaat erneut deklarieren, wird die Aussaat überschrieben.

0
KSHMR

Aktualisiert, um zu beachten, dass diese Antwort falsch ist! Der Grund dafür, dass meine Datenbank nicht geimpft wird, bleibt ein Rätsel (aber es fehlte nicht der von @JaredReisinger festgestellte Standardaufruf für Basiskonstruktoren

Ich schätze, dass diese Frage ein bisschen alt ist, aber ich bin hier gelandet, damit es jemand anderes könnte. Ist hier mein tuppence Wert:

Meine Datenbank wurde einwandfrei erstellt, aber nicht geimpft, auch wenn ich die Datenbank gelöscht und DropDatabaseInitialiser erneut verwendet habe.

Nachdem ich den obigen Code gelesen hatte, bemerkte ich, dass dies mein Kontextkonstruktor war

public MyApp_Context()
{
    // some code
}

das obige Beispiel würde für mein Setup wie folgt aussehen

public MyApp_Context() : base("name=MyApp_Context")
{
    // some code
}

Ja, ich habe den Konstruktor des Basisobjekts nicht aufgerufen! Ich hätte nicht erwartet, dass in diesem Fall alles außer Seeding funktioniert, aber das scheint der (wiederholbare) Fall zu sein.

NB, ich muss den Kontextnamen nicht im Basiskonstruktor-Aufruf angeben. Ich habe es anfangs nur so geschrieben, weil ich das Format der obigen Lösung kopiert habe. Mein Code lautet jetzt also so, und Seeding funktioniert bei der ersten Datenbankerstellung.

public MyApp_Context() : base()
{
    // some code
}
0
Jon

Das Startereignis in Ihrem Beispiel wird nur einmal ausgelöst, wenn Sie DropCreateDatabaseIfModelChanges verwenden. Sie können dies in DropCreateDatabase ändern. Ich denke, es sollte jedes Mal das Startereignis auslösen.

Bearbeiten

Das ist mein DataContext

public WebContext()
{   
    DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>());
}
0
Richard Forrest

Das ist mir gerade passiert, als ich Code First Features entdeckt habe. Diese Situation tritt häufig auf, wenn Sie zum ersten Mal Code First verwendet haben, um Ihre Datenbank ohne Initialisierungsstrategie zu generieren.

Wenn Sie sich später dazu entschließen, indem Sie eine DropCreateDatabaseIfModelChanges -basierte Strategie implementieren, ohne Ihr Modell zu ändern, wird Ihre Seed -Methode nicht aufgerufen, da die Datenbankgenerierung und Ihre Strategie nur so sein werden wird beim nächsten Modellwechsel angewendet.

Wenn Ihnen dies passiert, versuchen Sie einfach, Ihr Modell ein wenig zu modifizieren, um diese Hypothese zu testen, und ich wette, Ihre Datenbank wird gefüllt;)

Ich habe die Lösung noch nicht, außer eine Strategie zu verwenden, die immer die Datenbank generiert, aber ich bin mit der Tatsache, dass die Initialisierungsstrategie in Ihren DbContext eingefügt wird, wirklich nicht einverstanden, da diese Klasse in Ihrer Produktionsumgebung verwendet werden soll. Die Initialisierungsstrategie scheint jedoch hauptsächlich für fließende Entwicklungsumgebungen verwendet zu werden.

0
Bruno