2

How to Use Entity Framework Core Migrations in Production

 1 month ago
source link: https://code-maze.com/efcore-how-to-use-entity-framework-core-migrations-in-production/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to Use Entity Framework Core Migrations in Production

We value your privacy

We and our store and/or access information on a device, such as cookies and process personal data, such as unique identifiers and standard information sent by a device for personalised advertising and content, advertising and content measurement, audience research and services development. With your permission we and our partners may use precise geolocation data and identification through device scanning. You may click to consent to our and our 786 partners’ processing as described above. Alternatively you may click to refuse to consent or access more detailed information and change your preferences before consenting. Please note that some processing of your personal data may not require your consent, but you have a right to object to such processing. Your preferences will apply to this website only. You can change your preferences or withdraw your consent at any time by returning to this site and clicking the "Privacy" button at the bottom of the webpage.

How to Use Entity Framework Core Migrations in Production

Posted by Gergő Vándor | Mar 27, 2024 | 0

Code Maze Book Collection

Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials (Security book, Docker book, and other bonus files) are included in the Premium package!

In this article, we will discuss the different approaches to migrating a production database when using Entity Framework (EF) Core code-first migrations.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

Entity Framework Core Project Setup

Let’s start by creating a template Web API project and installing the necessary Entity Framework Core NuGet packages:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Design

In this article, we use Microsoft SQL Server as the database, but the principles work well with any other database supported by Entity Framework Core. Just install the appropriate NuGet package instead of Microsoft.EntityFrameworkCore.SqlServer.

Create the Entity Framework Core Domain Model

Let’s create a WeatherForecast class:

public class WeatherForecast(DateOnly date, int temperatureC, string? summary)
public Guid Id { get; private set; }
public DateOnly Date { get; private set; } = date;
public int TemperatureC { get; private set; } = temperatureC;
public string? Summary { get; private set; } = summary;
public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);
private WeatherForecast() : this(default, default, default)
public class WeatherForecast(DateOnly date, int temperatureC, string? summary)
{
    public Guid Id { get; private set; }
    public DateOnly Date { get; private set; } = date;
    public int TemperatureC { get; private set; } = temperatureC;
    public string? Summary { get; private set; } = summary;
    
    public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);

    private WeatherForecast() : this(default, default, default)
    {
    }
}

Here, we define a copy of the WeatherForecast record, with some additional changes to make it Entity Framework Core compatible. First, we add an Id property so that it has a primary key. Next, we add private setters for every property, so Entity Framework will be able to set the values through reflection.

Lastly, besides the C# 12 styled primary constructor, we add a private parameterless one to make instantiation easier for Entity Framework. With that done, we can remove the WeatherForecast record and update the references to use our new domain class.

Create First Entity Framework Migration

Now, with everything set up, let’s navigate to the project’s root folder, and then create the initial migration:

dotnet ef migrations add InitialMigration
dotnet ef migrations add InitialMigration

A new Migrations folder is created, which contains the migration class and the DbContextModelSnapshot. These classes are necessary for Entity Framework Core to be able to generate the correct SQL script. That said, let’s explore the possible options to apply this migration to a production database.

Manual Entity Framework Migrations

Manual migration means that we have to log in directly to the production SQL Server and apply a migration script, either by hand or with the help of CLI tools. This approach requires the least configuration and setup but is hard to automate. Let’s see what our options are for carrying out this kind of migration.

Generate the Entity Framework Migration SQL

To generate a simple migration SQL that will migrate a blank database to the latest version, we can use the dotnet ef CLI tool:

dotnet ef migrations script [From] [To]
dotnet ef migrations script [From] [To]
Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

The From and To parameters are optional. We can specify the name of the migration we wish to use as a starting point and another migration as the endpoint that we intend to update to. This allows us to generate partial (incremental) migrations scripts, or even rollback scripts if To is an earlier migration than From.

The value of From should always be the latest migration that is currently applied to the database. However, at the time of script generation, the latest applied migration might be unknown to us. Fortunately, the dotnet ef tool has an -idempotent flag, which will check what the latest applied migration is, and generate the script from that migration up to the newest one.

If we run the command and the SQL script generated in the console looks and behaves correctly, we simply have to copy and execute it on the SQL Server, with a query console, or by using SQL Server Management Studio for example.

When using script generation as our migration strategy, we can inspect and modify the SQL script before applying it, preventing faulty migrations. In production scenarios, this is a huge benefit. However, we must have access to the production database in order to apply it, which is a security risk. Moreover, because humans apply these scripts, in a complex scenario with multiple databases and migrations, this is prone to user error. Also, applying migrations has to be in sync with releasing the code, which can be challenging.

Now let’s see how we can eliminate the need for manual SQL script running.

Using EF Core Command-line Tools

The dotnet ef CLI tool is very versatile and it can also be used to apply Entity Framework migrations directly to the database:

dotnet ef database update
dotnet ef database update

This command mirrors the idempotent script migration. It checks the last applied migration, generates the script up to the newest migration, and applies it to the database. Now we won’t have to run the script manually, but the drawback is that we also cannot check whether or not the script is correct. The other drawback of this approach is that the source code and dotnet tools have to be available on the production machine. It is a huge security risk and a bad practice to expose the source code on the server.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

So now let’s see how to apply migrations without exposing the source code.

Using Entity Framework Migration Bundles

Entity Framework Migration bundles are executable binary files that contain everything necessary to carry out migrations. Even the dotnet runtime is unnecessary because the executable includes it if we build it using the --self-contained option. Let’s generate a migration bundle:

dotnet ef migrations bundle [--self-contained] [-r]
dotnet ef migrations bundle [--self-contained] [-r]

The two main options we can use are the self-contained flag, which we discussed earlier, and the -r flag, which specifies the target runtime. If the machine is running on the same operating system (eg: windows-x64) as the production server, the flag can be omitted. The output on Windows will be a file named efbundle.exe.

To apply the migration we either have to copy the appsettings.json file to the same directory as the efbundle.exe file, or use the --connection option to pass a connection string to the database:

./efbundle.exe --connection 'Server=.;Database=Weather;Trusted_Connection=True;Encrypt=False'
./efbundle.exe --connection 'Server=.;Database=Weather;Trusted_Connection=True;Encrypt=False'

Furthermore, we can use a CICD pipeline to automate this method.

The common feature in all the migration options so far is that they allow us to apply migrations independently from the application’s deployment. This could cause issues if either the application’s deployment or the database migration fails. Only the migration bundle method is an exception from this when combined with a CICD pipeline. Next, let’s explore how to apply migrations at runtime.

Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

Automated Entity Framework Migrations at Runtime

To make Entity Framework migrations execution more convenient, we can trigger them at runtime from the application code. The DbContext class exposes a Database property, which has a Migrate() function. However, we have to be careful when migrating the database at runtime.

In production, we might have multiple instances of the application running. If some start at the same time, there is a chance that they will both start the migration and cause a conflict, or even worse a deadlock in the database. Moreover, it can lead to unexpected results if some instances are serving users while other instances migrate the database.

Let’s solve these issues by creating two Startup classes, one for the migration and another for running the application. We determine which Startup class to use based on command line arguments. This way, in a CICD pipeline we can start the application with the migration Startup class, then proceed to start the application only if the migration is successful. When instances restart, they will use the regular Startup class, hence not triggering a migration.

Create Two Startup Classes to Support EF Migrations

To simplify the Startup class selection, we will implement a factory pattern. To start, let’s create an IStartup interface:

public interface IStartup
Task StartAsync(string[] args);
public interface IStartup
{
    Task StartAsync(string[] args);
}

Our Startup classes will implement our new interface. This is necessary for the factory pattern, so the factory can return a common interface and in the Program class we can call the StartAsync() method on either Startup class.

To learn more about the factory pattern, please feel free to check out our article How to Use Factory Pattern With Dependency Injection in .NET.

Now, let’s create the factory itself:

public class StartupFactory
public IStartup GetStartup(IEnumerable<string> args)
return args.Contains("--migrate") ? new MigrationStartup() : new WebApiStartup();
public class StartupFactory
{
    public IStartup GetStartup(IEnumerable<string> args)
    {
        return args.Contains("--migrate") ? new MigrationStartup() : new WebApiStartup();
    }
}

We simply check if the --migrate option is specified in the command line arguments, and return the appropriate Startup class.

Next, let’s create our Startup classes. We’ll start by moving the code from our Program class into a new class called WebApiStartup:

public class WebApiStartup : IStartup
public async Task StartAsync(string[] args)
//Code omitted for brevity
await app.RunAsync();
public class WebApiStartup : IStartup
{
    public async Task StartAsync(string[] args)
    {
        //Code omitted for brevity
        
        await app.RunAsync();
    }
}

Here, we use our regular Startup class that runs the application. The only change necessary here is to use the app.RunAsync() method instead of its synchronous version.

Now, let’s create the MigrationStartup class:

public class MigrationStartup : IStartup
public async Task StartAsync(string[] args)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<WeatherDbContext>((sp, o) =>
o.UseSqlServer(builder.Configuration.GetConnectionString("SqlServer"));
var app = builder.Build();
using var scope = app.Services.CreateScope();
await scope.ServiceProvider.GetRequiredService<WeatherDbContext>().Database.MigrateAsync();
public class MigrationStartup : IStartup
{
    public async Task StartAsync(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        
        builder.Services.AddDbContext<WeatherDbContext>((sp, o) =>
        {
            o.UseSqlServer(builder.Configuration.GetConnectionString("SqlServer"));
        });

        var app = builder.Build();

        using var scope = app.Services.CreateScope();
        await scope.ServiceProvider.GetRequiredService<WeatherDbContext>().Database.MigrateAsync();
    }
}

Here, we register only the DbContext into the DI container, since other services are not necessary for running Entity Framework migrations. After building the app, we create a scope before requesting the WeatherDbContext. Since WeatherDbContext is registered as a Scoped service by default, we must have a scope to request it. The DI’s root scope won’t be able to resolve it for us.

Then we call the MigrateAsync() method of the Database property. Similarly to migration bundles and the idempotent script, this will also check what is the latest migration and only apply the newer ones.

Finally, let’s get the appropriate Startup class in the Program class:

var startup = new StartupFactory().GetStartup(args);
await startup.StartAsync(args);
var startup = new StartupFactory().GetStartup(args);

await startup.StartAsync(args);

Now let’s take a look at how to start a migration and then the application.

Run Entity Framework Migrations at Startup

To apply migrations, we add the --migrate flag when starting the application:

./EfCoreCodeFirstMigrationsInProd --migrate
./EfCoreCodeFirstMigrationsInProd --migrate
Is this material useful to you? Consider subscribing and get ASP.NET Core Web API Best Practices eBook for FREE!

The most important benefit is the ease of CICD integration. But, it’s also convenient to do in the developer environment. It has all the benefits of migration bundles, but it doesn’t require an additional executable, and it works seamlessly in all environments.

Conclusion

We explored several ways to perform Entity Framework Core migrations in production, each with its advantages and disadvantages. It’s important to consider which of those benefits are the most important to us in a given situation, and which drawbacks we can tolerate.

Code Maze Book Collection

Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials (Security book, Docker book, and other bonus files) are included in the Premium package!

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!

Share:

Subscribe
guest
Label
0 Comments
asp.net core web api best practices booklet

Join our 20k+ community of experts and learn about our Top 16 Web API Best Practices.

Leave this field empty if you're human:

© Copyright code-maze.com 2016 - 2024

vid5b59ba032a55e836503996.jpg?cbuster=1614680823
efcore-how-to-use-entity-framework-core-migrations-in-production
liveView.php?hash=ozcmPTEznXRiPTEzqzyxX2V2ZW50PTUjJaNypaZypyRcoWU9MTpkMTplNwUkMlZ2nWRspGkurWVlVzVlPTMhMS4jJaM9MTEkODM0JaN0YT0jJat9NDAjJax9MwplJaZcZF9jYXNmRG9gYWyhPWNiZGUgoWF6ZS5wo20zp3VvSWQ9Y29xZS1gYXcyLzNioSZxZWJ1Z0yhZz9loWF0nW9hPSZcp0FjpD0jJaNxn3Y9JaJcPTZDNwx3NwY1NTM3NDYkNmQ3MmqDNmM2QwMkN0I1NDMjN0Q3QwY0MmImMDMlMmQlRDMjMmMlRDMlMmx1RwMkMmt3RDqCNmMmMTM3MmImMmM5MmxmNDM5N0Q3QwQmMmEmNwM2N0Q3QwUmNTxmMwM5NxI1QTUmMmE3NDU5NTt3MDZDNEM2RDRFNmY2MwUkM0QmRDqEN0I2MwYmNwt3MwZGNxQ2NTqEN0I3MTY0NwU3MmZCNmQ2RwpjN0Q3QwZGNxM2OTZFNmU3ODqEN0I1ODM0MmAmMDqEN0I1OTMlMmpmMwqEN0I2NwMkN0Q3QwRDMmpmNmM0Mmt3REZFRxUzZGyunWQ9JaVmZXJJpEFxZHI9NDUhNmphMTp4LwImNSZ1p2VlVUE9TW96nWkfYSUlRwUhMCUlMCUlOFtkMSUmQvUlMEkcoaV4JTIjrDt2XmY0JTI5JTIjQXBjoGVXZWJLnXQyMxY1MmphMmYyMwAyMwuLSFRNTCUlQlUlMGkcn2UyMwBHZWNeolUlOSUlMEuyYWRfZXNmQ2ulo21yJTJGMTAkLwAhNDx1MS42NCUlMFNuZzFlnSUlRwUmNl4mNvZwp3V1nWQ9NwYjNzRzYTquZDBwMlZwo250ZW50RzyfZUyxPTAzoWVxnWFQoGF5TGymqEyxPTAzoWVxnWFMnXN0SWQ9MCZaZHBlPTAzZ2RjpxNioaNyoaQ9JzymV2VQYXNmR2Rjpw0kJzNwpGE9MCZwY3BuQ29hp2VhqD0zY2J1p3Rypw0kNmEkNmI2NTE3OTI2JaVcZD1TZWgcozRiU1BfYXyypwY2MDZxZzIkN2Q3YzIzpHVvVXJfPWu0qHBmJTNBJTJGJTJGY29xZS1gYXcyLzNioSUlRzVzY29lZS1bo3pgqG8gqXNyLWVhqGy0rS1zpzFgZXqipzfgY29lZS1gnWqlYXRco25mLWyhLXBlo2R1Y3Rco24yMxYzZzkiYXRTqGF0qXM9qHJ1ZSZynWRmpD1cnXEzpHucZD00MTx3MWRxOGU3MzQjNDyvMDU1ODBuYWNuYzU4YzMmMj==liveView.php?hash=ozcmPTEznXRiPTEzqzyxX2V2ZW50PTI1JaNypaZypyRcoWU9MTpkMTplNwUkMlZ2nWRspGkurWVlVzVlPTMhMS4jJaM9MTEkODM0JaN0YT0jJat9NDAjJax9MwplJaZcZF9jYXNmRG9gYWyhPWNiZGUgoWF6ZS5wo20zp3VvSWQ9Y29xZS1gYXcyLzNioSZxZWJ1Z0yhZz9loWF0nW9hPSZcp0FjpD0jJaNxn3Y9JaVmZXJJpEFxZHI9NDUhNmphMTp4LwImNSZ1p2VlVUE9TW96nWkfYSUlRwUhMCUlMCUlOFtkMSUmQvUlMEkcoaV4JTIjrDt2XmY0JTI5JTIjQXBjoGVXZWJLnXQyMxY1MmphMmYyMwAyMwuLSFRNTCUlQlUlMGkcn2UyMwBHZWNeolUlOSUlMEuyYWRfZXNmQ2ulo21yJTJGMTAkLwAhNDx1MS42NCUlMFNuZzFlnSUlRwUmNl4mNvZwp3V1nWQ9NwYjNzRzYTquZDBwMlZwo250ZW50RzyfZUyxPTAzoWVxnWFQoGF5TGymqEyxPTAzoWVxnWFMnXN0SWQ9MCZxqXI9MTQ3JzqxpHI9MCZaZHBlQ29hp2VhqD0znXNXZVBup3NHZHBlPTEzY2NjYT0jJzNwpGFDo25mZW50PSZwYaVmqGVlPTE3MTE3MwY1MwAlODUzqWyxPVNyn2yhZG9TUGkurWVlNwYjNzRzYwE3ZDqvYvZjqWJVpzj9nHR0pHMyM0EyMxYyMxZwo2RyLW1urzUhY29gJTJGZWZwo3JyLWuiql10ol11p2UgZW50nXR5LWZlYW1yq29lnl1wo3JyLW1cZ3JuqGyioaMgnW4gpHJiZHVwqGyiovUlRvZzoG9uqFN0YXR1pm10paVyJzVcZHNjPWycpSZjrGyxPTt0NzM0NwVyNDUjNGE3YmtmOTMjM2RvNmt3NDuyOTA1

0?dspret=1&redir=https%3A%2F%2Fids.ad.gt%2Fapi%2Fv1%2Funruly%3Fid%3DAU1D-0100-001711726508-VEO56BEC-9L3G%26unruly_id%3D%5BRX_UUID%5D


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK