16

I have a DatabaseInitializer class

public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext>
{
    protected override void Seed
        (
        DatabaseContext databaseContext
        )
    {
        // Seed the hash methods.
        var defaultHashMethod = new HashMethod
        {
            Description = "Default",
            CreateDate = DateTime.Now
        };

        databaseContext.HashMethod.Add(defaultHashMethod);

        databaseContext.SaveChanges();
    }
}

In my DatabaseContext class I set the initializer

public DatabaseContext() : base("DatabaseContext")
{
    InitializeDatabase();
}

private void InitializeDatabase()
{
    Database.SetInitializer(new DatabaseInitializer());
    if (!Database.Exists())
    {
        Database.Initialize(true);
    }            
}

As far as I can understand the seed method is only invoked once you perform an operation such as a query. My database is created successfully and I'm querying the table, but the seed method is never called.

Update:

It seems like the problem is caused because of a class that is inheriting from my DatabaseContext class, when using this class to perform database operations, the seed method is not called. When using my DatabaseContext class, everything works as expected

public DbSet<TestEntity> TestEntity { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
Andre Lombaard
  • 6,985
  • 13
  • 55
  • 96

7 Answers7

16

You need to call Update-Database from the Package Manager Console.

jumuro
  • 1,517
  • 15
  • 17
  • 11
    The problem is when you do this the seed method is not called sometimes. – rollsch Dec 22 '16 at 07:04
  • 6
    for CI, we often don't want to run `Update-Database` from the console. Many people prefer to do it automatically through Web/App.config settings. This way the process is automated and you can easily migrate changes in a new PR to the DB before the PR's tests are run. Otherwise, it defeats the purpose of CI when the builds fail, requiring a dev to go run `update-databse` themselves... – Kris Coleman Feb 17 '18 at 19:12
8

The only way I could get this to work was to call the seed method myself

Here are the methods for my DatabaseContext class

 public DatabaseContext() : base("DatabaseContext")
 {
    InitializeDatabase();
 }

 public DatabaseContext(string connectionString) : base(connectionString)
 {
     Database.Connection.ConnectionString = connectionString;
     InitializeDatabase();
 }

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
 }

Here I changed my InitializeDatabase method from

private void InitializeDatabase()
{
    Database.SetInitializer(new DatabaseInitializer());
    if (!Database.Exists())
    {
        Database.Initialize(true);
    }            
}

to

protected virtual void InitializeDatabase()
{
    if (!Database.Exists())
    {
        Database.Initialize(true);
        new DatabaseInitializer().Seed(this);
    }            
}
Andre Lombaard
  • 6,985
  • 13
  • 55
  • 96
  • Thanks - I did something similar but more hacky, essentially burning out this part of EF and taking control of seeding explicitly. It seems like Update-Database uses a different enough codepath to make life hell when you want to make non-demo apps. – John Shedletsky Feb 19 '15 at 08:59
  • 9
    Thanks @user65439. Would be nice if this fixes it, but the `Seed()` method is `protected`! Because it's an override you can not change the accessor to `public`. And because it's not public you cannot call that method in `DatabaseInitializer` from the `DatabaseContext` class as your code example shows (I get a compile error). I don't get it, what am I missing? – Bart Nov 19 '15 at 10:54
  • This solution is the hack and new DatabaseInitializer().Seed(this); will not work because Seed method it is protected. I even do not see any point to call DatabaseInitializer in this context. Just place seed code instead of new DatabaseInitializer().Seed(this); – Tomas Oct 17 '17 at 11:38
  • This is not the only instance of this - there is another solution here : https://stackoverflow.com/questions/36024400/migratedatabasetolatestversion-no-running-seed-method - I have no idea why this is happening though, both answers are workarounds to an actual problem I believe – David Hiblen Dec 03 '18 at 15:57
5

This can happen if your Update-Database command does not run successfully, and this does not necessarily mean that it errors out. There might be changes that EF recognizes as "outstanding" that need to be added to a migration.

Try calling "Add-Migration {migrationNameHere}" and then try "Update-Database" again.

  • Thanks! This worked for me. Apparently I had an outstanding migration to add. Once I did that the seed was called. – Karl Morosiuk Jan 07 '21 at 18:57
  • Really strange, but this worked for me too. I created a dummy migration, with nothing generated inside it, and when starting the application the Seed was called (after the migrations). – Bob Lokerse Sep 21 '21 at 11:40
4

to get Seed method to be called when you are not using AutomaticMigration, you should use MigrateDatabaseToLatestVersion initializer for your code-first database.
like this:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<YourContext,YourConfiguration>());  

this way, Seed method will be called every time the migration is done successfully.

Amir Oveisi
  • 1,668
  • 1
  • 16
  • 25
  • This is causing to execute the seed every time a request is sent to db and generates the error 'Sequence contains more than one element' second time onwards, why? – FLash Sep 12 '18 at 10:05
  • As the Summary of the (base) Seed method says, you have to be careful and put in checks, so that it can run multiple times. The AddOrUpdate will check for that, depending if have the first parameter correct. (the field(s) that is(are) unique for the check). – Bob Lokerse Sep 21 '21 at 11:21
1

I had this issue and the problem was my Context constructor did not use the same name as in my web.config.

malckier
  • 1,052
  • 2
  • 14
  • 22
1

If you are using Code-First then you can populate the data when the application runs for the first time.

  • Create a DbInitializer

    public class MyDbInitializer : IDatabaseInitializer<MyDbContext>
    {
       public void InitializeDatabase(MyDbContext context)
       {
          if (context.Database.Exists())
          {
            if (!context.Database.CompatibleWithModel(true))
            {
                context.Database.Delete();
            }
          }
          context.Database.Create();
    
          User myUser = new User()
          {
            Email = "a@b.com",
            Password = "secure-password"
          };
          context.Users.AddOrUpdate<User>(p => p.Email, myUser);
          context.SaveChanges();
       }
    }
    
  • Register this DbInitializer in your Global.asax.cs Application_Start method

    Database.SetInitializer(new My.namespace.MyDbInitializer());
    
FAHID
  • 3,245
  • 3
  • 18
  • 15
0

My seed was not being executed either. However, it was because I added a column to a model that I had no intention of using in my actual database and forgot to use the [NotMapped] annotation.

    [NotMapped]
    public string Pair { get; set; }

There was no error message relating to this being the cause at all. Just a null reference to my repository obj when I tried to query data that should have been there.

midohioboarder
  • 438
  • 5
  • 14