Add Nocr.TextMatcher.Migrator

This commit is contained in:
Sergey Nazarov 2024-03-30 11:31:23 +03:00
parent f97b14ac0e
commit 65f03d2e20
16 changed files with 150 additions and 45 deletions

View File

@ -25,9 +25,11 @@
</ItemGroup>
<ItemGroup Label="Microsoft">
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="$(MicrosoftVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="$(MicrosoftVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftVersion)" />
</ItemGroup>
<ItemGroup Label="EntityFramework">
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />

View File

@ -28,6 +28,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nocr.TextMatcher.Persistenc
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Contracts", "Contracts", "{0B8E28B3-EECC-4981-A87F-6D74C4F23371}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nocr.TextMatcher.Migrator", "src\Nocr.TextMatcher.Migrator\Nocr.TextMatcher.Migrator.csproj", "{6C429E86-0344-40C2-8898-BBA551E50403}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -66,6 +68,10 @@ Global
{D578EE54-B55A-4B45-859D-7F343C73EEF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D578EE54-B55A-4B45-859D-7F343C73EEF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D578EE54-B55A-4B45-859D-7F343C73EEF5}.Release|Any CPU.Build.0 = Release|Any CPU
{6C429E86-0344-40C2-8898-BBA551E50403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C429E86-0344-40C2-8898-BBA551E50403}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C429E86-0344-40C2-8898-BBA551E50403}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C429E86-0344-40C2-8898-BBA551E50403}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B721E055-84AF-44C6-973D-33241FD2EA7C} = {6E4D9F75-861F-4C00-A5C8-00D1BEE5A659}

View File

@ -0,0 +1,2 @@
export DOTNET_ENVIRONMNET=Development
dotnet ef migrations add $1

View File

@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using Nocr.TextMatcher.Persistence;
namespace Nocr.TextMatcher.Migrator;
public class DesignTimeTextMatcherContextFactory : IDesignTimeDbContextFactory<TextMatcherContext>
{
private const string EnvironmentVariableKey = "DOTNET_ENVIRONMENT";
public TextMatcherContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<TextMatcherContext>();
var configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
var environment = configuration.GetValue<string>(EnvironmentVariableKey);
if (string.IsNullOrWhiteSpace(environment))
{
throw new InvalidOperationException($"Отсутствует переменная окружения {EnvironmentVariableKey}");
}
var connectionString = configuration.GetConnectionString(environment);
if (string.IsNullOrWhiteSpace(connectionString))
throw new InvalidOperationException($"ConnectionString for environment `{environment}` not found");
optionsBuilder.UseMySql(connectionString, new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion),
builder => builder.MigrationsAssembly("Nocr.TextMatcher.Migrator"));
return new TextMatcherContext(optionsBuilder.Options);
}
}

View File

@ -0,0 +1,19 @@
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet nuget add source -n "musk.fun.nocr" "https://gitea.musk.fun/api/packages/nocr/nuget/index.json"
RUN dotnet restore "src/Nocr.TextMatcher.Migrator/Nocr.TextMatcher.Migrator.csproj"
WORKDIR "/src/src/Nocr.TextMatcher.Migrator"
RUN dotnet build "Nocr.TextMatcher.Migrator.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Nocr.TextMatcher.Migrator.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Nocr.TextMatcher.Migrator.dll"]

View File

@ -9,10 +9,10 @@ using Nocr.TextMatcher.Persistence;
#nullable disable
namespace Nocr.TextMatcher.Persistence.Migrations
namespace Nocr.TextMatcher.Migrator.Migrations
{
[DbContext(typeof(TextMatcherContext))]
[Migration("20240328201810_InitialMigration")]
[Migration("20240330082504_InitialMigration")]
partial class InitialMigration
{
/// <inheritdoc />
@ -25,7 +25,7 @@ namespace Nocr.TextMatcher.Persistence.Migrations
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Nocr.TextMatcher.AppServices.TextMatches.TextSubscription", b =>
modelBuilder.Entity("Nocr.TextMatcher.AppServices.TextSubscriptions.TextSubscription", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()

View File

@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Nocr.TextMatcher.Persistence.Migrations
namespace Nocr.TextMatcher.Migrator.Migrations
{
/// <inheritdoc />
public partial class InitialMigration : Migration

View File

@ -8,7 +8,7 @@ using Nocr.TextMatcher.Persistence;
#nullable disable
namespace Nocr.TextMatcher.Persistence.Migrations
namespace Nocr.TextMatcher.Migrator.Migrations
{
[DbContext(typeof(TextMatcherContext))]
partial class TextMatcherContextModelSnapshot : ModelSnapshot
@ -22,7 +22,7 @@ namespace Nocr.TextMatcher.Persistence.Migrations
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Nocr.TextMatcher.AppServices.TextMatches.TextSubscription", b =>
modelBuilder.Entity("Nocr.TextMatcher.AppServices.TextSubscriptions.TextSubscription", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()

View File

@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
<None Remove="appsettings.json" />
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nocr.TextMatcher.Persistence\Nocr.TextMatcher.Persistence.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore;
namespace Nocr.TextMatcher.Migrator;
public class Program
{
public static async Task Main(string[] args)
{
var contextFactory = new DesignTimeTextMatcherContextFactory();
using (var context = contextFactory.CreateDbContext(Array.Empty<string>()))
{
await context.Database.MigrateAsync();
await context.SaveChangesAsync();
var appliedMigrations = await context.Database.GetAppliedMigrationsAsync();
Console.WriteLine("Applied migrations:");
foreach (var appliedMigration in appliedMigrations)
{
Console.WriteLine(appliedMigration);
}
}
}
}

View File

@ -0,0 +1,10 @@
# Nocr.TextMatcher.Migrator
Проект содержит консольное приложение для применения миграций к БД.
Для выбора строки подключения при запуске необходимо передать переменную окружения `DOTNET_ENVIRONMENT`. Для локальной разработки следует использовать `DOTNET_ENVIRONMENT=Development`.
## Добавление миграций
В приложении реализована логика выбора строки подключения, а dotnet ef не позволяет передать переменную окружения. Поэтому был создан скрипт AddMigration, который устанавливает значение `DOTNET_ENVIRONMENT=Development`.
Пример использования: `./AddMigration MyMigration`

View File

@ -0,0 +1,6 @@
{
"ConnectionStrings": {
"Development": "server=localhost;port=3306;database=nocr_text_matcher;uid=root;pwd=toor",
"DockerCompose": "server=nocr-text-matcher-db;port=3306;database=nocr_text_matcher;uid=root;pwd=toor"
}
}

View File

@ -1,22 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace Nocr.TextMatcher.Persistence;
public class DesignTimeTextMatcherContextFactory : IDesignTimeDbContextFactory<TextMatcherContext>
{
public TextMatcherContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<TextMatcherContext>();
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var connectionString = configuration.GetConnectionString("MariaLocal");
optionsBuilder.UseMySql(connectionString,
new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion));
return new TextMatcherContext(optionsBuilder.Options);
}
}

View File

@ -10,8 +10,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" />
</ItemGroup>
@ -19,11 +17,4 @@
<ProjectReference Include="..\Nocr.TextMatcher.AppServices\Nocr.TextMatcher.AppServices.csproj" />
</ItemGroup>
<ItemGroup>
<None Remove="appsettings.json" />
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@ -21,8 +21,7 @@ public static class ServiceCollectionExtensions
services.AddDbContext<TextMatcherContext>(
(ctx, context) =>
{
context.UseMySql(connectionString, new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion),
builder => builder.MigrationsAssembly(typeof(TextMatcherContext).Assembly.FullName))
context.UseMySql(connectionString, new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion))
.UseLoggerFactory(ctx.GetRequiredService<ILoggerFactory>());
}
);

View File

@ -1,5 +0,0 @@
{
"ConnectionStrings": {
"MariaLocal": "server=localhost;port=3306;database=nocr_text_matcher;uid=root;pwd=toor"
}
}