web-dev-qa-db-fra.com

Comment puis-je amorcer ma base de données en utilisant Entity Framework Code First?

La base de données est créée avec succès (comme le sont les tables) mais n'est pas amorcée. J'ai passé plusieurs heures et lu des tonnes d'articles mais je n'ai pas pu l'obtenir. Aucune suggestion?

Soit dit en passant, est-il possible d'appeler l'initialiseur sans avoir de référence à mon DatabaseContext dans le client?

J'ai inclus tout le code pertinent auquel je pouvais penser. Si quelque chose d'autre vous serait utile, faites-le moi savoir.

Choses que j'ai essayées:

  1. J'ai supprimé ma chaîne de connexion (car elle est par défaut sqlexpress de toute façon, seul le nom a changé)
  2. J'ai changé DropCreateDatabaseIfModelChanges en DropCreateDatabaseAlways, toujours le même.

Edit: La chose vraiment bizarre est que cela a fonctionné une fois, mais je ne sais pas comment ni pourquoi il s'est cassé à nouveau. J'assume des chaînes de connexion, mais qui sait.

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>

SOLUTION

Par souci de documentation, je partage ma solution ici. Parcourir tous les commentaires serait de toute façon une douleur. À la fin, j'avais DatabaseInitializer et DatabaseContext dans des classes distinctes. Je ne comprends pas vraiment pendant que ces petits changements le corrigeaient, mais le voici.

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

Voici à quoi ressemblent toutes mes classes DbContext et elles se comportent très bien:

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

J'ai utilisé ce modèle plusieurs fois et cela a très bien fonctionné pour moi.

37
Jim D'Angelo

Ma méthode Seed n'a pas été invoquée même avec un appel correct à Database.SetInitializer dans Application_Start... La raison en était très simple: l'initialiseur ne peut pas être invoqué du tout si vous n'avez pas encore de code tilise en fait contexte de base de données.

10
user1068352

Ceci est mon triste petit conte.

Premièrement, les leçons apprises:

  1. La méthode de départ ne sera appelée que lorsque le contexte sera utilisé.
  2. Le Global.asax.cs n'atteindra pas un point d'arrêt lors de la première exécution car il s'exécute avant que le débogueur ne soit attaché. Pour atteindre un point d'arrêt sur Global.asax.cs, vous pouvez ajouter un espace blanc à Web.config et frapper une page; alors il sera touché.
  3. S'il existe des connexions VS à la base de données, l'amorçage ne se produira pas. L'application générera une erreur.

Donc, pour éviter la tristesse:

  • Déconnectez votre connexion VS.
  • Basculez la classe de base DropCreateDatabaseAlways d'une seule fois.
  • Frappez une page qui utilise le contexte.

Maintenant, la tristesse:

  1. J'avais ma classe Initializer personnalisée dans mon fichier Global.asax.cs. J'ai eu un point d'arrêt sur mon initialiseur Seed; j'ai démarré l'application et la méthode n'a jamais été touchée. :(
  2. Je pointe un point d'arrêt dans mon appel Database.SetInitializer dans Application_Start. Cela n'a jamais été touché. :(
  3. J'ai réalisé que je n'avais aucun changement de schéma db, alors j'ai changé DropCreateDatabaseIfModelChanges en DropCreateDatabaseAlways. Toujours rien. :(
  4. Je suis finalement allé sur une page qui utilise le contexte, et cela a fonctionné. : /
9
Davious

Tu peux appeler update-database pour exécuter manuellement la méthode de départ dans la classe Configuration. Cela nécessite enable-migrations être également activé.

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

Le changement suivant dans le fichier Global.asax a fonctionné pour moi:

Ancien code:

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

Nouveau code:

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

J'ai moi aussi eu du mal à invoquer Seed (). Et j'apprécie toutes les suggestions utiles ci-dessus et j'ai eu de la chance en utilisant DropCreateDatabaseAlways ... mais pas TOUJOURS !!

Plus récemment, j'ai ajouté la ligne de code suivante dans le constructeur de mon référentiel à bon escient:

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

    }

Il suffisait de déclencher l'invocation de Seed (). Si vous avez tout essayé au-dessus de cette réponse et que vous n'avez toujours pas de chance, essayez-le. Bonne chance, c'était vraiment une expérience longue.

1
Joe

J'avais le même problème et après un changement dans les deux Global.asax fichier et Intializer fichier cela a fonctionné. J'espère que cela fonctionnera pour ceux qui ont encore des problèmes pour l'ensemencement des données.

Nouveau code dans Global.asax:

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

code pour le fichier Intializer:

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

Je viens de rencontrer ce problème. J'ai supprimé la section "connectionstrings" du fichier Web.config, et actuellement l'application a commencé à fonctionner - sans la section connectionstrings! J'ajoute la section en arrière, et la base de données ne se réenserre pas. Ce n'est pas une bonne solution, mais j'ajoute simplement un point de données ici à ce qui peut potentiellement résoudre le problème.

Heureusement, c'est juste une petite application "jetable" que je vais bientôt jeter de toute façon ...

0
Evgeny

Assurez-vous méticuleusement que vous n'avez pas déclaré votre variable de contexte plus d'une fois. Si vous le déclarez à nouveau après l'ensemencement, la graine sera écrasée.

0
KSHMR

Mis à jour pour noter que cette réponse est incorrecte! La raison pour laquelle ma base de données n'a pas été semée reste un mystère (mais ce n'était pas l'absence d'un appel de constructeur de base par défaut, comme l'a noté @JaredReisinger)

J'apprécie que cette question soit un peu vieille mais je me suis retrouvée ici pour que quelqu'un d'autre puisse le faire. Voici ma valeur de tuppence:

Ma base de données était bien créée mais pas prédéfinie, même si j'ai supprimé la base de données et recommencé à utiliser DropDatabaseInitialiser.

Après avoir lu le code ci-dessus, j'ai remarqué que mon constructeur de contexte était ce

public MyApp_Context()
{
    // some code
}

alors que l'exemple ci-dessus serait le suivant pour ma configuration

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

Ouais, je n'appelais pas le constructeur de l'objet de base! Je ne m'attendais pas à ce que tout sauf l'ensemencement fonctionne dans ce cas, mais cela semble être le cas (répétable).

NB, je n'ai pas vraiment besoin de fournir le nom du contexte dans l'appel du constructeur de base; Je ne l'ai écrit que de cette façon au départ parce que je copiais le format de la solution ci-dessus. Donc, mon code est maintenant ceci, et l'amorçage fonctionne sur la création initiale de la base de données.

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

L'événement de départ dans votre exemple ne sera déclenché qu'une seule fois lorsque vous utilisez DropCreateDatabaseIfModelChanges, vous pouvez le changer en DropCreateDatabaseAlways, je pense et il devrait déclencher l'événement de départ à chaque fois.

Modifier

Ceci est mon DataContext

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

Cela m'est juste arrivé alors que je découvrais les fonctionnalités de Code First. Cette situation se produit souvent lorsque vous avez d'abord utilisé Code First pour générer votre base de données sans aucune stratégie d'initialisation.

Si vous décidez de le faire plus tard en implémentant une stratégie basée sur DropCreateDatabaseIfModelChanges, mais sans modifier votre modèle, votre méthode Seed ne sera pas appelée car la génération de la base de données et votre stratégie ne seront appliqué la prochaine fois que vous changez de modèle.

Si cela vous arrive, essayez de modifier un peu votre modèle pour tester cette hypothèse et je parie que votre base de données va être peuplée;)

Je n'ai pas encore la solution, sauf en utilisant une stratégie qui génère toujours la base de données, mais je ne suis vraiment pas à l'aise avec le fait de mettre la stratégie d'initialisation dans votre DbContext car cette classe est destinée à être utilisée dans votre environnement de production, Bien que la stratégie d'initialisation semble être principalement utilisée pour un environnement de développement fluide.

0
Bruno