I have an ASP.Net Core application which uses Entity Framework with Sqlite. I am building a Docker image to deploy this.
The ASP.Net Core application runs fine when debugging with VS Code, but when running in a Docker container I receive an error:
SqliteException: SQLite Error 1: 'no such table: MyTable'.
I figured this is because I need to run the Entity Framework migrations when I build the Docker image. I have added dotnet ef database update
to my Dockerfile, which looks like:
FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
RUN dotnet ef database update
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "MyApplication.dll"]
The image builds without errors. However, when I create a container and look at the database, it is empty with no tables.
What is the correct way to set up a database with Entity Framework when building a Docker image?
Migrations are enabled by default in EF Core. They are managed by executing commands. If you have Visual Studio, you can use the Package Manager Console (PMC) to manage migrations. Alternatively, you can use a command line tool to execute Entity Framework CLI commands to create a migration.
Run the Enable-Migrations –EnableAutomaticMigrations command in Package Manager Console This command has added a Migrations folder to our project. This new folder contains one file: The Configuration class. This class allows you to configure how Migrations behaves for your context.
For anyone on .net 6 I used this to apply migrations at startup just before app.Run() in Program.cs file
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
if (context.Database.GetPendingMigrations().Any())
{
context.Database.Migrate();
}
}
Regardless of your deployment type, you can Apply migrations at runtime on your Startup class at the very end of your Configure method, e.g. calling the following method:
public void ApplyMigrations(ApplicationDbContext context) {
if (context.Database.GetPendingMigrations().Any()) {
context.Database.Migrate();
}
}
A couple of things:
1) A RUN command in a Dockerfile is an instruction executed during the build of the container image - so it will run once (and probably fail because there's no database) where you are building the image rather than when you later run the image.
2) I would recommend separating performing migrations from the deployment of a new version of your container. You may only be running a single copy of the container at the moment, but if you ever ran 2 or more then you would have multiple containers all checking to see if they should run migrations and that could cause issues. There's also the problem that you have deployed code that depends upon the migration, but you don't yet know that the migration will work - better to run the migrations first, and if they fail, don't deploy the new container.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With