Основы DbContext и DbSet
Настройте DbContext, определите сущности, задайте строку подключения и выполните свой первый запрос.
«Основы DbContext и DbSet» — бесплатный урок C# Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Что такое Entity Framework Core
EF Core — официальный объектно-реляционный преобразователь (ORM) для .NET. Он сопоставляет классы C# (сущности) с таблицами базы данных и позволяет запрашивать и сохранять данные с помощью LINQ — для большинства операций SQL не требуется.
Определение сущности
Сущность — это обычный класс C#, свойства которого сопоставляются со столбцами базы данных. По соглашению свойство с именем Id или <TypeName>Id становится первичным ключом.
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
public int Stock { get; set; }
public DateTime CreatedAt { get; set; }
}Создание DbContext
DbContext — это точка доступа к базе данных. Он содержит свойства DbSet<T> для каждой сущности и управляет подключением, отслеживанием изменений и транзакциями.
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
public DbSet<Product> Products => Set<Product>();
public DbSet<Order> Orders => Set<Order>();
}Регистрация DbContext в DI
Вызовите AddDbContext в Program.cs, чтобы зарегистрировать контекст как сервис с временем жизни Scoped и настроить поставщика базы данных.
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("Default")));
// For SQLite (great for development/testing):
// options.UseSqlite("Data Source=app.db");Базовые запросы с DbSet
DbSet<T> предоставляет операторы LINQ. Запросы не выполняются, пока их результаты не будут перечислены (await ...ToListAsync()). Это называется отложенным выполнением.
public class ProductService
{
private readonly AppDbContext _db;
public ProductService(AppDbContext db) => _db = db;
public async Task<List<Product>> GetExpensiveAsync(decimal minPrice)
{
return await _db.Products
.Where(p => p.Price >= minPrice)
.OrderBy(p => p.Name)
.ToListAsync();
}
}Поиск по первичному ключу
FindAsync сначала проверяет локальный кэш отслеживания изменений, а уже затем обращается к базе данных. Используйте его при запросе по первичному ключу, чтобы избежать лишних обращений к базе данных.
var product = await _db.Products.FindAsync(42);
if (product is null)
throw new KeyNotFoundException("Product not found");
// For complex keys, pass all key values:
var orderLine = await _db.OrderLines.FindAsync(orderId, productId);Добавление новых записей
Вызовите Add, чтобы поставить сущность в очередь на добавление, а затем вызовите SaveChangesAsync для фиксации изменений. EF Core генерирует SQL-оператор INSERT и заполняет автоматически сгенерированный Id.
var product = new Product
{
Name = "Mechanical Keyboard",
Price = 149.99m,
Stock = 50,
CreatedAt = DateTime.UtcNow
};
_db.Products.Add(product);
await _db.SaveChangesAsync();
Console.WriteLine(product.Id); // Auto-generated PKОбновление записей
Сущности, загруженные EF Core, отслеживаются. Изменяйте свойства напрямую и вызывайте SaveChangesAsync — EF Core обнаружит изменения и сгенерирует оптимизированный оператор UPDATE.
var product = await _db.Products.FindAsync(42);
if (product is not null)
{
product.Price = 129.99m;
product.Stock -= 1;
await _db.SaveChangesAsync(); // UPDATE Products SET Price=...
}Удаление записей
Вызовите Remove, чтобы пометить сущность на удаление, а затем вызовите SaveChangesAsync. Используйте ExecuteDeleteAsync (начиная с .NET 7) для массового удаления без загрузки сущностей.
// Delete a tracked entity
_db.Products.Remove(product);
await _db.SaveChangesAsync();
// Bulk delete without loading (EF Core 7+)
await _db.Products
.Where(p => p.Stock == 0)
.ExecuteDeleteAsync();Настройка с помощью Fluent API
Переопределите OnModelCreating, чтобы настроить сущности с помощью Fluent API: имена таблиц, типы столбцов, ограничения, индексы и связи.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>(entity =>
{
entity.ToTable("products");
entity.Property(p => p.Name).IsRequired().HasMaxLength(200);
entity.Property(p => p.Price).HasColumnType("decimal(18,2)");
entity.HasIndex(p => p.Name);
});
}Практика: репозиторий на основе DbContext
Типичный репозиторий оборачивает DbContext, чтобы централизовать логику доступа к данным и скрыть детали запросов от классов сервисов.
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _db;
public ProductRepository(AppDbContext db) => _db = db;
public async Task<Product?> GetByIdAsync(int id)
=> await _db.Products.AsNoTracking().FirstOrDefaultAsync(p => p.Id == id);
public async Task<List<Product>> SearchAsync(string query)
=> await _db.Products
.Where(p => p.Name.Contains(query))
.AsNoTracking()
.ToListAsync();
}Быстрая проверка
Что делает AsNoTracking() при выполнении запроса с EF Core?
Итоги: основы DbContext и DbSet
Главное:
- DbContext — это сеанс работы с базой данных; DbSet<T> представляет таблицу
- Зарегистрируйте его с помощью
AddDbContextв DI; по умолчанию он имеет время жизни Scoped - Запросы LINQ выполняются отложенно — запустите их с помощью
ToListAsyncилиFirstOrDefaultAsync - Отслеживание изменений позволяет автоматически выполнять UPDATE/DELETE через SaveChangesAsync
- Используйте
AsNoTracking()для запросов только на чтение, чтобы повысить производительность
Часто задаваемые вопросы
Урок «Основы DbContext и DbSet» бесплатный?
Да — полный текст урока «Основы DbContext и DbSet» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Основы DbContext и DbSet»?
Настройте DbContext, определите сущности, задайте строку подключения и выполните свой первый запрос. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Основы DbContext и DbSet»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы DbContext и DbSet
- Миграции и управление схемой
- Операции CRUD с EF Core
- Связи: один-ко-многим и многие-ко-многим