Author : HASSAN MD TAREQ

DBSeeder

  • create utility class DBSeeder.cs
  • use context.Database.Migrate() instead of context.Database.EnsureCreated(); (EnsureCreated() does not use migrations to create the database and therefore the database that is created cannot be later updated using migrations)

DBSeeder.cs

public class DBSeeder
{

	public static void Seed(EmployeeDbContext context)
	{
		// context.Database.EnsureCreated() does not use migrations to create the database and therefore the database that is created cannot be later updated using migrations 
		// use context.Database.Migrate() instead
		context.Database.Migrate();

		if (context.Employees.Any())
		{
			return;
		}

		// insert dummy data
		context.AddRange(GetDummyEmployeeList());
		context.SaveChanges();
	}


	public static List<Employee> GetDummyEmployeeList()
	{
		var employees = new List<Employee> {
			new Employee{ FirstName = "Foo", LastName = "Bar", Boss = "boss 1", Address = "address 1", DateOfBirth =  DateTime.Today.AddYears(-1), Salary = 1_000_000.0 },
			new Employee{ FirstName = "first_name 2", LastName = "last_name 2", Boss = "boss 2", Address = "address 2", DateOfBirth =  DateTime.Today.AddYears(-2), Salary = 2_000_000.0 },
			new Employee{ FirstName = "first_name 3", LastName = "last_name 3", Boss = "boss 3", Address = "address 3", DateOfBirth =  DateTime.Today.AddYears(-3), Salary = 3_000_000.0 },
			new Employee{ FirstName = "first_name 4", LastName = "last_name 4", Boss = "boss 4", Address = "address 4", DateOfBirth =  DateTime.Today.AddYears(-4), Salary = 4_000_000.0 },
			new Employee{ FirstName = "first_name 5", LastName = "last_name 5", Boss = "boss 5", Address = "address 5", DateOfBirth =  DateTime.Today.AddYears(-5), Salary = 5_000_000.0 },
			new Employee{ FirstName = "first_name 6", LastName = "last_name 6", Boss = "boss 6", Address = "address 6", DateOfBirth =  DateTime.Today.AddYears(-6), Salary = 6_000_000.0 },
			new Employee{ FirstName = "first_name 7", LastName = "last_name 7", Boss = "boss 7", Address = "address 7", DateOfBirth =  DateTime.Today.AddYears(-7), Salary = 7_000_000.0 },
			new Employee{ FirstName = "first_name 8", LastName = "last_name 8", Boss = "boss 8", Address = "address 8", DateOfBirth =  DateTime.Today.AddYears(-8), Salary = 8_000_000.0 },
			// ... ... ...
		};

		return employees;
	}
}

Use DBSeeder in Main method of Program

  • recommend : use the Configure method only to set up the request pipeline. Application startup code belongs in the Main method. See: Move database initialization code
  • get a database context instance from the dependency injection container
  • call the seed method, passing to it the context
  • dispose the context when the seed method is done

Program.cs

public class Program
{
	public static void Main(string[] args)
	{
		var host = CreateWebHostBuilder(args).Build();
		
		using (var scope = host.Services.CreateScope())
		{
			var services = scope.ServiceProvider;
			try
			{
				var context = services.GetRequiredService<EmployeeDbContext>();
				DBSeeder.Seed(context);
			}
			catch (Exception ex)
			{
				var logger = services.GetRequiredService<ILogger<Program>>();
				logger.LogError(ex, "An error occurred while seeding the database.");
			}
		}

		host.Run();
	}

	public static IWebHostBuilder CreateWebHostBuilder(string[] args)
	{
		return WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();
	}
}

Auto Migration

  • best approach: https://stackoverflow.com/questions/37780136/asp-core-migrate-ef-core-sql-db-on-startup
  • data initialization code should be in Main method
  • code below is not recommended because UpdateDatabase() is in Configure() (move UpdateDatabase() to Main method if possible)

Startup.cs

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        UpdateDatabase(app);
        // ... ... ...
    }

    private static void UpdateDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            using (var context = serviceScope.ServiceProvider.GetService<FooDbContext?())
            {
                context.Database.Migrate();
            }
        }
    }