Ты, наверное, ошибаешься в перемещениях ЭФП... (Українська (Ukrainian))

Ты, наверное, ошибаешься в перемещениях ЭФП...

Sunday, 23 November 2025

//

9 minute read

Працює MigrateAsync() Під час запуску? Ви надаєте вашим програмам права власника бази даних і сподіваєтеся, що нічого не станеться. Є кращий спосіб - Міграції EC дозволяють вам запускати міграцію як контрольований крок CI, утримуючи ваш комп' ютерний додаток. Але ось дещо: іноді " wrong " насправді непоганий. Давайте розглянемо, коли слід використовувати кожен підхід.

Офіційні документи: Огляд міграцій | Як застосовувати міграцію | БундлесCity in New Jersey USA

Wrong" way (який я використовую)

Цей блог використовує MigrateAsync() ось чому це добре для мене і чому це можливо не для тебе.

В моєму Program.cs У мене є файл:

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

MigrateAsync() застосувати пересилання з черги і за потреби створити базу даних. Просте, але проблема:

  1. Залежність від запуску - Переміщення зазнає невдачі?
  2. Порушення безпеки - Ваш додаток потребує db_owner Ты только что дал своему программу ключи, чтобы бросить столы.

Чому мені це не вдається: публічні дані, єдина мережа Докера, персональний проект. Ти, мабуть, не можеш.

Коли перельоти у вільний час є добрими

  • Локальний dev - Швидка ітерація б'є церемонія.
  • Особисті проекти - Низький радіус вибуху, без чутливих даних
  • Докер- комбінація середовищ dev - Зручність перемагає
  • Прострочення - Схема постійно змінюється

Коли це не так

  • Декілька екземплярів програм - Расові умови шаленіють
  • Відчутливі дані - PII, фінансовий, регульований = належне розділення потрібно
  • Виробництво за допомогою реальних користувачів - Невдача міграції =outage

Правий шлях: EC Bundle

Смуга EF - це самодостатній виконуваний файл, у якому містяться ваші компіляції. Думайте про те, що dotnet ef database update пакунок у окремому місці .exe.

Чому перемагають пучки:

  • Немає залежностей під час виконання - Ціль не потребує SDK або EF CLI
  • Належне роз'єднання - App ніколи не потрібна db_owner; Робить лише інструмент запуску CI, лише під час виконання
  • Видимість CI - Невдачі, які показуються у каналах трубопроводів, а не поховані під час запуску програм
  • Забезпечення зворотним зв' язком - Переміщення зазнає невдачі?
  • Ідепотент - Стежить за застосуванням, виконує тільки те, що потрібно

Примітка: Для безпеки виробництва, використовуйте Керований профіль Але снопи все - таки є основним кроком до перельоту через бігові перельоти.

Приклад дій GitHub

      - name: Install EF Core tools
        run: dotnet tool install --global dotnet-ef

      - name: Add EF tools to PATH
        run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH

      - name: Generate EF migration bundle
        run: |
          dotnet ef migrations bundle \
            --project ${{ env.WEB_PROJECT }} \
            --output efbundle.exe \
            --configuration ${{ env.BUILD_CONFIGURATION }} \
            --runtime ${{ env.RUNTIME_IDENTIFIER }} \
            --context AdminDbContext \
        env:
          AdminSite__ConnectionString: ${{ secrets.PROD_SQL_CONNECTIONSTRING }}

      - name: Run EF migration bundle
        run: |
          ./efbundle.exe
        env:
          AdminSite__ConnectionString: ${{ secrets.PROD_SQL_CONNECTIONSTRING }}

П' ятчик читає рядки з' єднання зі змінних середовища і застосовує перельоти з черги. Вже застосовано? Він просто успішно завершує роботу.

Локальні форми

Без CI? не хочете перевірити перед тим, як натискати? Зберіть вузли локально.

Випадки використання: Тестування перед CI, DBA whichoff (вбудований приклад, без використання SDK), блокування, усування вад з --verbose.

Як створити бендл

# Install EF CLI (once)
dotnet tool install --global dotnet-ef

# Basic bundle
dotnet ef migrations bundle \
    --project Mostlylucid.DbContext \
    --startup-project Mostlylucid \
    --output efbundle.exe

# Self-contained (includes runtime - portable to machines without .NET)
dotnet ef migrations bundle \
    --project Mostlylucid.DbContext \
    --startup-project Mostlylucid \
    --output efbundle.exe \
    --self-contained

# Cross-platform (e.g., build on Windows, deploy to Linux)
dotnet ef migrations bundle \
    --project Mostlylucid.DbContext \
    --startup-project Mostlylucid \
    --output efbundle \
    --runtime linux-x64

Як працювати над своєю будовою

# Using default connection string from appsettings.json
./efbundle.exe

# Override with a specific connection string
./efbundle.exe --connection "Host=localhost;Database=mostlylucid;Username=postgres;Password=secret"

# Using an environment variable (matches your config key)
$env:ConnectionStrings__DefaultConnection="Host=localhost;..." # PowerShell
export ConnectionStrings__DefaultConnection="Host=localhost;..." # Bash
./efbundle.exe

Корисні параметри бондле

# See what migrations would be applied without running them
./efbundle.exe --dry-run

# Verbose output for debugging
./efbundle.exe --verbose

# Apply migrations up to a specific migration (useful for testing)
./efbundle.exe --target-migration "20231115_AddUserTable"

# Combine options
./efbundle.exe --verbose --dry-run

Локальний процес тестування

# 1. Create migration
dotnet ef migrations add AddNewFeature \
    --project Mostlylucid.DbContext \
    --startup-project Mostlylucid

# 2. Build bundle
dotnet ef migrations bundle \
    --project Mostlylucid.DbContext \
    --startup-project Mostlylucid \
    --output efbundle.exe

# 3. Dry run first
./efbundle.exe --dry-run --verbose

# 4. Run for real
./efbundle.exe --verbose

# 5. Broken? Remove and retry
dotnet ef migrations remove \
    --project Mostlylucid.DbContext \
    --startup-project Mostlylucid

Перехоплює синтаксичні помилки, обмеження, проблеми з FK - all до СІ або виробництво.

Швидкодія збирання

Покоління бундлів є повільним - 30+секунд на великих проектах.

  • Створювати вручну під час локальної перевірки
  • Створювати у CI лише під час виконання, не всі PR
  • Вузли кешу, якщо міграцій не змінено

Якщо ви справді бажаєте автоматичного створення, додайте ціль MSBuild:

<Target Name="BuildMigrationBundle">
  <Exec Command="dotnet ef migrations bundle --output $(OutputPath)efbundle.exe --force" />
</Target>

Тоді: dotnet build -t:BuildMigrationBundle

Гібридний підхід

Найкращі з обох світів: зручність на місці, безпека у виробництві.

if (builder.Environment.IsDevelopment())
{
    using var scope = app.Services.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService<IMostlylucidDBContext>();
    await context.Database.MigrateAsync();
}
// Production: CI pipeline runs the bundle

Альтернативи для бондлів

Скрипти SQL

Створює простий SQL замість виконуваного файла. Чудово для аналізу DBA і існуючих процесів керування змінами.

# All migrations
dotnet ef migrations script --output migrations.sql

# Idempotent (safe to run multiple times) - USE THIS
dotnet ef migrations script --idempotent --output migrations.sql

# Range of migrations
dotnet ef migrations script FromMigration ToMigration --output migrations.sql

Прос: Повна видимість, будь-який клієнт SQL може запустити цю програму, дружній до версій керування версіями, програма у схваленні DBA.

Збори: Без автодосліджень (корисно) --idempotent), ручне виконання, потенційне дрейфування, якщо ви змінюєте скрипти.

Див. офіційні документи скриптів SQL.

Скрипти SQL у CI

- name: Generate and apply migrations
  run: |
    dotnet ef migrations script --idempotent --output migrations.sql
    # SQL Server
    sqlcmd -S ${{ secrets.DB_SERVER }} -d ${{ secrets.DB_NAME }} -i migrations.sql
    # Or PostgreSQL
    PGPASSWORD=${{ secrets.DB_PASSWORD }} psql -h ${{ secrets.DB_HOST }} -f migrations.sql

DACPAC (лише сервер SQL)

DACPACs є заснований на станах неDescription of a condition. Do not translate key words (# V1S #, # V1 #,) заснований на міграціях. Ви визначаєте бажану схему, а SqlPackage розшифрує її у базі даних призначення.

SqlPackage.exe /Action:Publish /SourceFile:MyDatabase.dacpac /TargetConnectionString:"..."

Прос: Схема як код, автоматичне створення різниці, керування всім (таблями, переглядами, SP, індексами), інструментами для роботи з підприємцями.

Збори: Тільки сервер SQL, схема у двох місцях (EF Modes + SQL project), рушій різниці робить сумнівний вибір, перейменування стовпчиків виглядає як floop+add.

Див. Документи SqlPackage.

Таблиця порівняння

Д'Ап-доріжка Ап-пайлі ДБА ДБО ДБІ ДБ |----------|----------|---------------|---------------------|--------------|-------------------| | MigrateAsync() Д_ д. д. д. д. д. д. д. д. д. д. д. д. д. Д-р Харріс: ♪SQ ZOGE-DBA керується середовищами ♪ Ні' з --idempotent Д. Так. *------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Підказки

Попався файл дизайнера

Міграції працюють у вашій місцевості, але не на ЦРУ? Перевірте, чи передано обидва файли:

  • 20231115_AddUserTable.cs - Код міграцій
  • 20231115_AddUserTable.Designer.cs - Знімок моделі

Відсутній файл Designer = безмовна помилка.

Декілька DbContexts

dotnet ef migrations bundle --context BlogDbContext --output blog-migrations.exe
dotnet ef migrations bundle --context IdentityDbContext --output identity-migrations.exe

Пріоритет рядків з' єднання

  1. --connection аргумент
  2. Змінна середовища
  3. appsettings.json

Використовувати змінні середовища у CI.

IDesignTimeDbContextFactory

EC- інструменти повинні миттєво втілювати ваш DbContext. Якщо ваш DbContext знаходиться у окремому проекті або має складний запуск, реалізацію IDesignTimeDbContextFactory<T>:

public class AdminDbContextFactory : IDesignTimeDbContextFactory<AdminDbContext>
{
    public AdminDbContext CreateDbContext(string[] args)
    {
        var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true)
            .AddEnvironmentVariables()
            .AddUserSecrets<AdminDbContextFactory>()
            .Build();

        var connectionString = config["AdminSite:ConnectionString"]
            ?? throw new InvalidOperationException("Missing connection string");

        var optionsBuilder = new DbContextOptionsBuilder<AdminDbContext>();
        optionsBuilder.UseSqlServer(connectionString, sql => sql.CommandTimeout(120));

        return new AdminDbContext(optionsBuilder.Options);
    }
}

Використовувати, якщо: DbContext у окремому проекті, комплексному запуску, потрібні таємниці користувача для дизайну.

Что насчет...?

Звичайні питання і відштовхування, які я отримав.

"Чому б просто не бігти dotnet ef database update У CI? "

Наведена вище, але коротка версія: пучки - це портативні артефакти. Ваш крок впровадження не потребує EC CLI, вихідного коду або роздільної здатності у режимі дизайну. Такий же вузол працює у тестах, застійах і прод - нуль дрейфів.

"Хіба це не забагато для маленької програми?"

Можливо. а радіус вибуху низький - MigrateAsync() Але як тільки ви додаєте ще один розробник, чутливі дані або багато середовищ, снопи платять самі за себе.

"А як щодо зворотних поворотів?"

EC не виконує автоматичних розкладок. Параметри:

  • Створити Down() міграція і запуск (але вам слід записати її)
  • Відновити з резервної копії
  • Записати вручну міграцію, щоб скасувати зміни

Для критичних систем: спочатку тест перелітає на клон бази даних.

"Чи можу я керувати міграціями у контейнері Kubernetes init?"

Так. Контейнер " Бондле + init " є суцільним шаблоном:

initContainers:
  - name: migrate
    image: myapp:latest
    command: ["./efbundle.exe"]
    env:
      - name: ConnectionStrings__Default
        valueFrom:
          secretKeyRef:
            name: db-secrets
            key: connection-string

Контейнер App чекає на завершення init.

"А як щодо FluentMigrator / DbUp / інших інструментів?"

Вони працюють чудово. Смуги ЄФ є еФ-нативним рішенням, але FluentMigrator і DbUp Ключова відмінність: ці інструменти є специфічними для міграцій, в той час як EF-групи походять від вашої EC-моделі.

"Моя DBA хоче переглянути всі SQL перед запуском"

Користування --idempotent скрипти:

dotnet ef migrations script --idempotent --output migrations.sql

DBA рецензування і схвалення.

  • Запустити скрипт вручну або
  • Після схвалення запустіть вузол (що робить те саме)

"Як мені впоратися з міграціями з нульовим спадом?"

Це питання стратегії розповсюдження, а не питання міграції.

  1. Робить міграцію зворотно сумісною (додайте стовпчики непридатними, не перейменовуйте)
  2. Впорядкувати новий код, який працює як зі старою, так і новою схемою
  3. Переміщення запуску
  4. Вкласти код, який використовує лише нову схему
  5. Очищення старих стовпчиків під час пізнішої міграції)

Бонделі не вирішують це - вони просто роблять крок 3 більш передбачуваним.

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.