Entity Framework Core (EF Core) — это мощный, легковесный и кроссплатформенный объектно-реляционный маппер (ORM) от Microsoft, который стал стандартом де-факто для работы с базами данных в .NET приложениях. Он позволяет разработчикам взаимодействовать с данными, используя объекты .NET, минимизируя необходимость в написании громоздкого SQL-кода. В этой статье мы погрузимся в практические примеры, которые помогут вам освоить EF Core от простых запросов до сложных сценариев.
Начало работы: базовая настройка и CRUD
Первым шагом является установка необходимых пакетов NuGet, например, Microsoft.EntityFrameworkCore.SqlServer для работы с SQL Server. Далее определяем модель данных (entity) и контекст базы данных (DbContext).
Пример 1: Определение модели и контекста
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public List Posts { get; set; } = new List();
}
public class BloggingContext : DbContext
{
public DbSet Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlServer(@\"Server=(localdb)\\mssqllocaldb;Database=BloggingDB;\");
}
Это основа. Контекст BloggingContext представляет сессию с базой данных, позволяя запрашивать и сохранять данные.
Используйте подход \"Code First\", когда вы сначала пишете классы сущностей, а EF Core создает или обновляет схему базы данных. Это наиболее гибкий и популярный метод.
Практические примеры операций с данными
Добавление данных (Create)
using (var db = new BloggingContext())
{
var blog = new Blog { Title = \"EF Core Tutorial\" };
db.Blogs.Add(blog);
db.SaveChanges(); // SQL INSERT выполняется здесь
}
Чтение данных (Read) с LINQ
EF Core тесно интегрирован с LINQ (Language Integrated Query).
var blogs = db.Blogs
.Where(b => b.Title.Contains(\"Tutorial\"))
.OrderBy(b => b.Id)
.ToList(); // Запрос выполняется при вызове ToList()
Обновление (Update) и удаление (Delete)
// Обновление
var blog = db.Blogs.Find(1);
if (blog != null)
{
blog.Title = \"Updated Title\";
db.SaveChanges(); // SQL UPDATE
}
// Удаление
db.Blogs.Remove(blog);
db.SaveChanges(); // SQL DELETE
Метод SaveChanges() является атомарным. Все изменения в контексте (добавления, обновления, удаления) фиксируются в базе данных одной транзакцией.
Продвинутые сценарии: связи, миграции и производительность
Настройка связей между сущностями
EF Core автоматически распознает связи по навигационным свойствам (как Posts в классе Blog). Но вы можете тонко настроить их с помощью Fluent API в методе OnModelCreating.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasMany(b => b.Posts)
.WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);
}
Миграции базы данных
Миграции — это способ последовательного обновления схемы базы данных в соответствии с изменяющейся моделью. После добавления нового свойства в класс Blog вы выполняете в консоли диспетчера пакетов:
Add-Migration AddUrlField
Update-Database
EF Core создаст и применит SQL-скрипт для добавления нового столбца.
Забота о производительности: AsNoTracking и Include
- AsNoTracking(): Указывает, что сущности не нужно отслеживать для изменений. Существенно ускоряет запросы, предназначенные только для чтения.
var blogs = db.Blogs.AsNoTracking().ToList(); - Include(): Позволяет явно загружать связанные данные (жадная загрузка), избегая проблемы N+1 запроса.
var blogsWithPosts = db.Blogs.Include(b => b.Posts).ToList();
FAQ: Часто задаваемые вопросы
В чем разница между EF Core и EF6?
EF Core — это переписанная с нуля, кроссплатформенная и более модульная версия. EF6 — это зрелый, но исключительно .NET Framework ORM. Для новых проектов на .NET 5/6/7+ всегда выбирайте EF Core.
Как выбрать стратегию загрузки связанных данных?
Используйте Include для жадной загрузки, когда связанные данные нужны сразу. Используйте явную загрузку (Load) или ленивую загрузку (Lazy Loading, требует установки прокси-пакета), когда данные нужны не всегда.
Что такое DbContext Pooling и зачем он нужен?
Это механизм повторного использования экземпляров DbContext, что снижает накладные расходы на их создание в веб-приложениях с высокой нагрузкой. Настраивается в Startup.cs или Program.cs.
Как выполнить сырой SQL-запрос?
Для сложных запросов используйте методы FromSqlRaw или ExecuteSqlRaw.
var blogs = db.Blogs.FromSqlRaw(\"SELECT * FROM Blogs WHERE Rating > {0}\", 5).ToList();
EF Core медленный. Что делать?
- Проверьте, не делаете ли вы N+1 запрос. Используйте
IncludeиAsNoTracking. - Используйте логирование (
LogToилиUseLoggerFactory) для просмотра генерируемого SQL. - Рассмотрите возможность использования Dapper для сложных отчетных запросов, сохраняя EF Core для операций CRUD.