Entity Framework Core на практике: от основ до продвинутых примеров для C# разработчика

Entity Framework Core на практике: от основ до продвинутых примеров для C# разработчика

Entity Framework Core (EF Core) — это мощный, легковесный и кроссплатформенный объектно-реляционный маппер (ORM) от Microsoft, который стал незаменимым инструментом для .NET разработчиков. Он позволяет работать с базами данных, используя знакомые объекты C#, избавляя от необходимости писать тонны шаблонного SQL-кода. В этой статье мы погрузимся в практические примеры, которые помогут вам освоить EF Core от простых запросов до сложных сценариев.

Что такое Entity Framework Core и зачем он нужен?

Представьте, что вам больше не нужно вручную прописывать каждый JOIN и WHERE. Вместо этого вы просто работаете с коллекциями объектов, а EF Core волшебным образом транслирует ваши операции в SQL-запросы. Это и есть его главная магия. Он поддерживает множество баз данных: SQL Server, PostgreSQL, MySQL, SQLite и другие.

EF Core — это эволюция классического Entity Framework. Он быстрее, модульнее и работает не только на Windows, но и на Linux и macOS благодаря .NET Core/.NET 5+.

Практические примеры: от простого к сложному

Лучший способ понять EF Core — увидеть его в действии. Рассмотрим ключевые сценарии.

1. Базовая настройка и модель данных

Сначала определим простые модели (сущности) и контекст базы данных (DbContext).

public class Blog
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Url { get; set; }
    public List Posts { get; set; } = new(); // Навигационное свойство
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int BlogId { get; set; } // Внешний ключ
    public Blog Blog { get; set; } // Навигационное свойство
}

public class BloggingContext : DbContext
{
    public DbSet Blogs { get; set; }
    public DbSet Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=BloggingDB;Trusted_Connection=True;");
}

2. CRUD-операции: создание, чтение, обновление, удаление

Работа с данными интуитивно понятна.

  1. Создание (Create):
    using var db = new BloggingContext();
    var blog = new Blog { Title = "EF Core Guide", Url = "https://example.com" };
    db.Blogs.Add(blog);
    await db.SaveChangesAsync(); // INSERT в БД
  2. Чтение (Read) с фильтрацией и включением связанных данных:
    var blogsWithPosts = await db.Blogs
        .Where(b => b.Title.Contains("Core"))
        .Include(b => b.Posts) // Жадная загрузка (Eager Loading)
        .ToListAsync();
  3. Обновление (Update):
    var blog = await db.Blogs.FindAsync(1);
    blog.Title = "Обновленное название";
    await db.SaveChangesAsync(); // UPDATE
  4. Удаление (Delete):
    var blog = await db.Blogs.FindAsync(1);
    db.Blogs.Remove(blog);
    await db.SaveChangesAsync(); // DELETE

Все изменения (Add, Update, Remove) накапливаются в памяти до вызова SaveChangesAsync(). Это позволяет объединять несколько операций в одну транзакцию.

3. Миграции базы данных

EF Core миграции — это система контроля версий схемы вашей БД. После изменения моделей выполните в консоли диспетчера пакетов (Package Manager Console):

  • Add-Migration InitialCreate — создает миграцию на основе текущих моделей.
  • Update-Database — применяет миграцию к БД, создавая или изменяя таблицы.

Это делает процесс эволюции схемы данных безопасным и воспроизводимым.

4. Выполнение сырых SQL-запросов

Иногда ORM не справляется со сложными запросами. Для этого есть возможность выполнить свой SQL:

var blogs = await db.Blogs
    .FromSqlRaw("SELECT * FROM Blogs WHERE Url LIKE '%example%'")
    .ToListAsync();

// Или для операций, не возвращающих сущности
await db.Database.ExecuteSqlRawAsync("DELETE FROM Posts WHERE BlogId = {0}", blogId);

Лучшие практики и частые ошибки

  • N+1 проблема: Избегайте циклических обращений к БД внутри циклов. Используйте .Include() или .ThenInclude() для жадной загрузки или .Select() для явной проекции.
  • Отслеживание изменений (Tracking): Для операций только для чтения используйте .AsNoTracking() для увеличения производительности.
  • Асинхронность: Всегда используйте асинхронные методы (ToListAsync(), SaveChangesAsync()) в веб-приложениях для масштабируемости.
  • Внедрение зависимостей (DI): В ASP.NET Core регистрируйте контекст в Startup.cs или Program.cs и внедряйте его в контроллеры через конструктор.

FAQ: Часто задаваемые вопросы по Entity Framework Core

В чем разница между Entity Framework и Entity Framework Core?

EF Core — это переписанная с нуля, кроссплатформенная и более легковесная версия классического EF. У него меньше "магии", но больше контроля и производительности. Для новых проектов всегда выбирайте EF Core.

Как выбрать стратегию загрузки связанных данных?

Есть три основных способа: Eager Loading (жадная, с помощью .Include()), Lazy Loading (ленивая, требует установки пакета и прокси-классов) и Explicit Loading (явная, с помощью .Entry().Collection().Load()). Для большинства сценариев, где вы заранее знаете, какие данные нужны, используйте Eager Loading.

Как улучшить производительность EF Core?

Ключевые моменты: используйте .AsNoTracking(), фильтруйте данные на стороне БД (в .Where()), а не в памяти, выбирайте только нужные поля с .Select(), используйте индексы в БД и минимизируйте количество запросов.

Поддерживает ли EF Core NoSQL базы данных?

Официально EF Core ориентирован на реляционные БД. Однако существуют сторонние провайдеры для некоторых NoSQL-систем, например, Cosmos DB имеет официального провайдера от Microsoft.

Стоит ли использовать EF Core в микросервисной архитектуре?

Да, но с осторожностью. Он отлично подходит для быстрой разработки внутри сервиса. Однако избегайте использования миграций EF Core для управления схемой БД в production-среде микросервисов — это может нарушить их независимость. Лучше использовать отдельные инструменты для миграций БД (например, Flyway, DbUp).