Entity Framework Core: работа с базой данных на примере

Введение:

В 2025 году разработка enterprise-приложений требует не просто доступа к данным, а интеллектуального управления объектно-реляционным преобразованием. Entity Framework Core эволюционировал из простого ORM в полноценную платформу для работы с данными, став критически важным инструментом в арсенале .NET-разработчика.

Почему EF Core перестал быть опциональным?

  • Скорость разработки — сокращение времени на написание boilerplate кода на 60-70%

  • Безопасность — автоматическая защита от SQL-инъекций и валидация данных

  • Производительность — умное кеширование, компилированные запросы, батчинг

  • Кроссплатформенность — единый API для SQL Server, PostgreSQL, MySQL, SQLite

Что изменилось в современных версиях?

  • EF Core 8 принес рекордную производительность и новые паттерны

  • Интеграция с облачными сервисами — Azure Cosmos DB, AWS Aurora

  • Поддержка сложных сценариев — JSON-колонки, полиморфные запросы, глобальные фильтры

  • Готовность к микросервисам — распределенные транзакции, шардинг


1. Создание моделей и контекста

1.1. Модели данных

public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime CreatedAt { get; set; }
public List<Comment> Comments { get; set; }
}

public class Comment
{
public int Id { get; set; }
public string Author { get; set; }
public string Text { get; set; }
public DateTime CreatedAt { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}

1.2. Контекст данных

public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

public DbSet<Blog> Blogs { get; set; }
public DbSet<Comment> Comments { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasMany(b => b.Comments)
.WithOne(c => c.Blog)
.HasForeignKey(c => c.BlogId);
}
}

2. Настройка и миграции

2.1. Регистрация в DI

services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString(«Default»)));

2.2. Создание миграции

dotnet ef migrations add InitialCreate
dotnet ef database update

3. Базовые CRUD-операции

3.1. Добавление данных

var blog = new Blog
{
Title = «EF Core Basics»,
Content = «Content…»,
CreatedAt = DateTime.UtcNow
};

context.Blogs.Add(blog);
await context.SaveChangesAsync();

3.2. Чтение данных

var blogs = await context.Blogs
.Where(b => b.CreatedAt > DateTime.UtcNow.AddDays(-7))
.OrderByDescending(b => b.CreatedAt)
.ToListAsync();

3.3. Обновление данных

var blog = await context.Blogs.FindAsync(1);
blog.Title = «Updated Title»;
await context.SaveChangesAsync();

3.4. Удаление данных

var blog = await context.Blogs.FindAsync(1);
context.Blogs.Remove(blog);
await context.SaveChangesAsync();

4. Сложные запросы и включения

4.1. Включение связанных данных

var blogsWithComments = await context.Blogs
.Include(b => b.Comments)
.Where(b => b.Comments.Any())
.ToListAsync();

4.2. Проекции

var blogTitles = await context.Blogs
.Select(b => new { b.Id, b.Title })
.ToListAsync();

4.3. Группировка

var commentsByAuthor = await context.Comments
.GroupBy(c => c.Author)
.Select(g => new { Author = g.Key, Count = g.Count() })
.ToListAsync();

5. Производительность и оптимизация

5.1. AsNoTracking

var blogs = await context.Blogs
.AsNoTracking()
.ToListAsync();

5.2. Разделение запроса

var blogs = await context.Blogs
.Include(b => b.Comments)
.AsSplitQuery()
.ToListAsync();

5.3. Кеширование

var blogs = await context.Blogs
.FromSqlRaw(«SELECT * FROM Blogs WITH (NOLOCK)»)
.ToListAsync();

6. Транзакции и управление состоянием

6.1. Явные транзакции

using var transaction = await context.Database.BeginTransactionAsync();

try
{
context.Blogs.Add(newBlog);
await context.SaveChangesAsync();

context.Comments.Add(newComment);
await context.SaveChangesAsync();

await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}

6.2. Неявные транзакции

var strategy = context.Database.CreateExecutionStrategy();

await strategy.ExecuteAsync(async () =>
{
using var context = new AppDbContext();
using var transaction = await context.Database.BeginTransactionAsync();

// Operations
await transaction.CommitAsync();
});

7. Работа с наследованием и полиморфизмом

7.1. TPH (Table per Hierarchy)

public abstract class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

public class Book : Product
{
public string ISBN { get; set; }
public int PageCount { get; set; }
}

public class Electronics : Product
{
public string Manufacturer { get; set; }
public int WarrantyMonths { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasDiscriminator<string>(«ProductType»)
.HasValue<Book>(«Book»)
.HasValue<Electronics>(«Electronics»);
}

7.2. Получение полиморфных данных

var products = await context.Products
.OfType<Book>()
.Where(b => b.PageCount > 100)
.ToListAsync();


Заключение

Entity Framework Core доказал, что ORM может быть не только удобным инструментом для быстрой разработки, но и высокопроизводительной платформой для enterprise-решений. Мы рассмотрели ключевые аспекты:

  1. Эффективное моделирование данных через Fluent API и отношения между сущностями

  2. Оптимизацию производительности с помощью компилированных запросов, отслеживания изменений и батчинга

  3. Расширенные возможности работы с наследованием, JSON-данными и сырыми SQL-запросами

  4. Интеграцию с экосистемой .NET через Dependency Injection и современные паттерны программирования

  5. Подходы к тестированию и обеспечению надежности данных

EF Core продолжает развиваться, предлагая разработчикам всё более мощные инструменты для работы с данными, сохраняя при этом обратную совместимость и предсказуемость поведения.


Для дальнейшего изучения

  1. Глобальные фильтры запросов для реализации multi-tenancy и soft delete

  2. Интерцепторы и перехватчики для кастомизации процесса сохранения

  3. Производительные миграции на больших базах данных с минимальным даунтаймом

  4. Работа с временными таблицами (Temporal Tables) для аудита изменений

  5. Интеграция с Dapper для гибридного подхода к доступу к данным

  6. Оптимизация для облачных сред с автоматическим решением проблем подключения

  7. Безопасность данных через шифрование на уровне приложения и БД