3

I am developing a .Net project. I am using entity framework code first approach to interact with database. I am seeding some mock data to my database during development. But seeding is not working. I followed this link - http://www.entityframeworktutorial.net/code-first/seed-database-in-code-first.aspx.

This is my ContextInitializer class

public class ContextInitializer : System.Data.Entity.CreateDatabaseIfNotExists<StoreContext>
    {

        protected override void Seed(StoreContext context)
        {
            IList<Brand> brands = new List<Brand>();
            brands.Add(new Brand { Name = "Giordano" ,TotalSale = 1 });
            brands.Add(new Brand { Name = "Nike" , TotalSale = 3 });

            foreach(Brand brand in brands)
            {
                context.Brands.Add(brand);
            }
            base.Seed(context);
            context.SaveChanges();

        }
    }

This is my context class

public class StoreContext : DbContext,IDisposable
    {
        public StoreContext():base("DefaultConnection")
        {
            Database.SetInitializer(new ContextInitializer());
        }

        public virtual DbSet<Category> Categories { get; set; }
        public virtual DbSet<Brand> Brands { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }
   }

This is my brand class

public class Brand
    {
        public int Id { get; set; }
        [Required]
        [MaxLength(40)]
        public string Name { get; set; }
        public int TotalSale { get; set; }
    }

I searched solutions online and I followed instructions. I run context.SaveChanges as well. But it is not seeding data to database. Why it is not working?

halfer
  • 19,824
  • 17
  • 99
  • 186
Wai Yan Hein
  • 13,651
  • 35
  • 180
  • 372

3 Answers3

3

You are taking the wrong initializer, CreateDatabaseIfNotExists is called only if the database not exists!

You can use for example DropCreateDatabaseIfModelChanges:

Solution 1)

public class ContextInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<StoreContext>
{

You have to take care with this approach, it !!!removes!!! all existing data.

Solution 2)

Create a custom DbMigrationsConfiguration:

public class Configuration : DbMigrationsConfiguration<StoreContext>
{
    public Configuration()
    {
        // Take here! read about this property!
        this.AutomaticMigrationDataLossAllowed = true;
        this.AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(StoreContext context)
    {
        IList<Brand> brands = new List<Brand>();
        brands.Add(new Brand { Name = "Giordano", TotalSale = 1 });
        brands.Add(new Brand { Name = "Nike", TotalSale = 3 });

        foreach (Brand brand in brands)
        {
            context.Brands.AddOrUpdate(m => m.Name, brand);
        }
        base.Seed(context);
        context.SaveChanges();
    }
}

In this way you can called( !!Before you create the DbContext or in the DbContext constructor!!):

// You can put me also in DbContext constuctor     
Database.SetInitializer(new MigrateDatabaseToLatestVersion<StoreContext , Yournamespace.Migrations.Configuration>("DefaultConnection"));

Notes:

  • DbMigrationsConfiguration need to know about the connection string you can provide this info in the constructor or from outside.
  • In Your DbMigrationsConfiguration you can configure also:
    • MigrationsNamespace
    • MigrationsAssembly
    • MigrationsDirectory
    • TargetDatabase

If you leave everything default as in my example then you do not have to change anything!

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Bassam Alugili
  • 16,345
  • 7
  • 52
  • 70
0

Setting the Initializer for a Database has to happen BEFORE the context is ever created so...

    public StoreContext():base("DefaultConnection")
    {
        Database.SetInitializer(new ContextInitializer());
    }

is much to late. If you made it static, then it could work:

    static StoreContext()
    {
        Database.SetInitializer(new ContextInitializer());
    }
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • I added this static StoreContext() { Database.SetInitializer(new ContextInitializer()); } below existing constructor. But it is not working. I cannot delete existing constructor cause It defines connection string and will throw error if I do. Please what is wrong with what i am doing please? – Wai Yan Hein Jul 06 '16 at 04:07
  • Oh. I think I need to add this to web.config file. But when I add, it says cannot set initializer. I set PatheinFashionStore.Domain.Concrete.StoreContext is my context class and PatheinFashionStore main project. So please is that correct. The way I am setting. – Wai Yan Hein Jul 06 '16 at 04:27
  • I have a feeling you don't understand [When is the Seed method called in a EF code first migrations scenario?](http://stackoverflow.com/questions/24142107/when-is-the-seed-method-called-in-a-ef-code-first-migrations-scenario). – Erik Philips Jul 06 '16 at 06:10
  • The Seed() method on the database initializer is invoked when database is creating and it doesn't handle existing data (seed from DbMigrationsConfiguration hanles them, checking if specified entities exist). – Erik Philips Jul 06 '16 at 14:55
0

Your code is working if you delete your existing database and the EF will create and seeding the data

Or

You can use DbMigrationsConfiguration insted of CreateDatabaseIfNotExists and change your code as follow:

First you have to delete the existing database

ContextInitializer class

public class ContextInitializer : System.Data.Entity.Migrations.DbMigrationsConfiguration<StoreContext>
{
    public ContextInitializer()
    {
        this.AutomaticMigrationDataLossAllowed = true;
        this.AutomaticMigrationsEnabled = true;
    }
    protected override void Seed(StoreContext context)
    {
        IList<Brand> brands = new List<Brand>();
        brands.Add(new Brand { Name = "Giordano", TotalSale = 1 });
        brands.Add(new Brand { Name = "Nike", TotalSale = 3 });

        foreach (Brand brand in brands)
        {
            context.Brands.AddOrUpdate(m => m.Name, brand);
        }
        base.Seed(context);
        context.SaveChanges();

    }
}

StoreContext

public class StoreContext : DbContext, IDisposable
    {
        public StoreContext() : base("DefaultConnection")
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<StoreContext, ContextInitializer>());
            //  Database.SetInitializer(new ContextInitializer());
        }

        public virtual DbSet<Category> Categories { get; set; }
        public virtual DbSet<Brand> Brands { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }
    }

Then any change in your seed will automatically reflected to your database

Abdul Hadi
  • 1,229
  • 1
  • 11
  • 20
  • If I inherit from DbMigrationsConfiguration, it throws error during compilation. – Wai Yan Hein Jul 06 '16 at 04:58
  • try to add using System.Data.Entity.Migrations; – Abdul Hadi Jul 06 '16 at 05:12
  • When I run, it throws exception "Unable to update database that matches the current model". When I update database from console, it is saying "More than one migrations configuration type was found in the assembly 'PatheinFashionStore.Domain'. Specify the name of the one to use.". I am using second way. – Wai Yan Hein Jul 06 '16 at 17:24