Entity FrameworkMiddleTechnical

В чём разница между подходами Code-First, Database-First и Model-First?

Code-First: модель в C#-классах, схема БД через миграции. Database-First: scaffold-команда генерирует классы из существующей БД. Model-First (только EF 6): устаревший визуальный дизайнер EDMX, в EF Core не поддерживается.

Три подхода к моделированию в Entity Framework

Entity Framework поддерживает три стратегии определения модели данных. Выбор зависит от того, что является источником истины: код, существующая БД или визуальная диаграмма.

Code-First

Модель описывается C#-классами (POCO). EF Core генерирует схему БД через миграции. Это единственный подход, который полноценно поддерживается в EF Core (EF 6 поддерживал все три).

// 1. Определяем классы
public class Order
{
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Status { get; set; } = "pending";
    public ICollection<OrderItem> Items { get; set; } = new List<OrderItem>();
}

public class OrderItem
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public Order Order { get; set; } = null!;
    public string ProductName { get; set; } = string.Empty;
    public decimal Price { get; set; }
}

// 2. Конфигурация через Fluent API
public class AppDbContext : DbContext
{
    public DbSet<Order> Orders => Set<Order>();
    public DbSet<OrderItem> OrderItems => Set<OrderItem>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .Property(o => o.Status)
            .HasMaxLength(50)
            .HasDefaultValue("pending");

        modelBuilder.Entity<OrderItem>()
            .Property(i => i.Price)
            .HasColumnType("decimal(18,2)");
    }
}

// 3. Создаём и применяем миграцию
// dotnet ef migrations add InitOrders
// dotnet ef database update

Database-First

Источник истины — существующая база данных. EF Core генерирует классы и DbContext с помощью команды scaffold (reverse engineering).

# Scaffolding из существующей БД (SQL Server)
dotnet ef dbcontext scaffold \
  "Server=.;Database=Shop;Trusted_Connection=True" \
  Microsoft.EntityFrameworkCore.SqlServer \
  --output-dir Models \
  --context ShopContext \
  --data-annotations \
  --force

# PostgreSQL
dotnet ef dbcontext scaffold \
  "Host=localhost;Database=shop;Username=postgres" \
  Npgsql.EntityFrameworkCore.PostgreSQL \
  --output-dir Models

Сгенерированные файлы не следует редактировать вручную — при повторном scaffolding они перезаписываются. Кастомизацию выносят в partial-классы.

Model-First (только EF 6)

Модель рисуется в визуальном дизайнере Visual Studio (.edmx-файл), из которого генерируются и классы, и схема БД. В EF Core этот подход не поддерживается — Microsoft считает его устаревшим и рекомендует Code-First.

Сравнительная таблица

  • Code-First: источник истины — C#-код; подходит для новых проектов; версионируется через миграции; поддерживается в EF Core.
  • Database-First: источник истины — SQL-схема; подходит для легаси-БД; код генерируется scaffolding-командой; поддерживается в EF Core.
  • Model-First: источник истины — EDMX-диаграмма; устарел; только EF 6; в EF Core отсутствует.

Подводные камни

  • При Database-First изменения схемы БД не попадают в модель автоматически — нужно повторно запускать scaffold с флагом --force, что перезаписывает кастомизации.
  • Code-First и Database-First нельзя смешивать для одной таблицы: это приведёт к конфликтам между ModelSnapshot и реальной схемой.
  • При scaffolding EF Core не всегда корректно распознаёт составные PK, check-constraints и специфичные для диалекта типы — требуется ручная доработка.
  • Model-First (EDMX) в EF 6 генерировал тяжёлый XML-файл с плохим разрешением конфликтов в git — одна из причин отказа от него в EF Core.
  • Code-First без миграций (EnsureCreated) не обновляет существующую схему — подходит только для тестов или первого запуска.
  • Database-First не генерирует историю миграций — при переходе на Code-First нужно вручную создать baseline-миграцию командой migrations add --ignore-changes.

Common mistakes

  • Путать Code-First, Database-First и исторический Model-First с похожим механизмом из другой версии или платформы.
  • Игнорировать runtime-границы Entity Framework: lifecycle, DI scope, SQL translation, UI thread или platform API.
  • Не обсуждать null/empty/error cases и поведение под нагрузкой.

What the interviewer is testing

  • Кандидат объясняет Code-First, Database-First и исторический Model-First на конкретном примере, а не только определением.
  • Указывает последствия для производительности, тестируемости и поддержки.
  • Различает документированное поведение текущего стека и устаревшие практики.

Sources

Related topics