Creating/Updating database schema from a console application

.net-core .net-core-3.0 c# entity-framework-core

Question

I have a console application that interacts with a backend database using EF. Core. I have the DBContext that looks as follows.

class HRDepartmentContext : DbContext
{
    public DbSet<Employee> Employee { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=somepath\\employees.db");
}

It's consumed in a class that looks as follows.

class EmployeeManager
{
    public  CreateEmployee(string firstname, string lastname)
    {
        using (var db = new EmployeeContext())
        {
            db.Database.EnsureCreated();

            // logic for employee creation
        }
    }

    // other methods for delete/update the employees
    public UpdateEmployee(...) {...}
    public DeleteEmployee(...) {...}
}

My questions.

a) What is the best way of calling EnsureCreated method as I don't want to call it in the individual Create/Update/Delete Employee methods.

b) What is the best way of handling schema changes scenarios in future versions of the application? Reading the documentation, it does not look like EsureCreated will be able to handle the scenario. Obviously upgrade schema need to be performed without any existing data loss.

UPDATE: I want to avoid using any EF command lines for migration in case of schema changes. I prefer the code to handle it.

1
0
2/3/2020 2:29:03 AM

Accepted Answer

Personally in netcore 3 I would use the generic IHost in your console application. Then configure the database services using dependency injection. And an IHostedService to create or migrate the database during startup.

    public class Program {
        public static void ConfigureServices(HostBuilderContext context, IServiceCollection serviceCollection)
        {
            serviceCollection.AddEntityFrameworkSqlite();
            serviceCollection.AddHostedService<DatabaseStartup>();

            serviceCollection.AddDbContextPool<HRDepartmentContext>(o =>
            {
                o.UseSqlite("Data Source=somepath\\employees.db");
            });
            // configure other services here
        }

        public static async Task<int> Main(string[] args)
        {
            using (var host = CreateHostBuilder(args).Build())
            {
                await host.StartAsync();
                var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();

                // insert other console app code here

                lifetime.StopApplication();
                await host.WaitForShutdownAsync();
            }
            return 0;
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host
                .CreateDefaultBuilder(args)
                .UseConsoleLifetime()
                .ConfigureServices(ConfigureServices);
    }

    public class DatabaseStartup : IHostedService {
        private readonly IServiceProvider serviceProvider;
        public DatabaseStartup(IServiceProvider serviceProvider){
            this.serviceProvider = serviceProvider;
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            using (var scope = serviceProvider.CreateScope())
            {
                var db = scope.ServiceProvider.GetRequiredService<HRDepartmentContext>();
                await db.Database.EnsureCreated();
                // or 
                await db.Database.MigrateAsync();
            }
        }

        public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
    }

Since your console application then has a CreateHostBuilder, the entity framework command line tools can discover any custom configuration when creating migrations.

1
2/3/2020 2:20:41 AM

Popular Answer

Also to create and employee you can use the class constructor, or the object initializer



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow