0Pricing
C# Academy · 강의

DbContext와 DbSet 기초

DbContext를 설정하고 엔터티를 정의하며 연결 문자열을 구성하고 첫 번째 쿼리를 실행합니다.

DbContext와 DbSet 기초은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

Entity Framework Core란 무엇인가요

EF Core는 공식 .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에서 호출하여 컨텍스트를 범위 지정 서비스로 등록하고 데이터베이스 공급자를 구성합니다.

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가 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 방식으로 구성하기

OnModelCreating을 재정의하여 Fluent 방식으로 엔터티를 구성합니다. 테이블 이름, 열 형식, 제약 조건, 인덱스 및 관계를 설정할 수 있습니다.

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();
}

빠른 확인

EF Core로 조회할 때 AsNoTracking()은 어떤 작업을 수행합니까?

복습: DbContext 및 DbSet 기본 사항

핵심 내용:

  • DbContext는 데이터베이스와의 세션이며, DbSet<T>은 테이블을 나타냅니다
  • DI에서 AddDbContext로 등록하며 기본적으로 범위 지정으로 설정됩니다
  • LINQ 쿼리는 지연 실행되며 ToListAsync, FirstOrDefaultAsync로 실행합니다
  • 변경 추적을 사용하면 SaveChangesAsync를 통해 UPDATE/DELETE를 자동으로 수행할 수 있습니다
  • 읽기 전용 쿼리에는 AsNoTracking()을 사용하여 성능을 향상합니다

자주 묻는 질문

“DbContext와 DbSet 기초” 강의는 무료인가요?

네 — “DbContext와 DbSet 기초” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“DbContext와 DbSet 기초”에서 뭘 배우나요?

DbContext를 설정하고 엔터티를 정의하며 연결 문자열을 구성하고 첫 번째 쿼리를 실행합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“DbContext와 DbSet 기초” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. DbContext와 DbSet 기초
  2. 마이그레이션과 스키마 관리
  3. EF Core를 사용한 CRUD 작업
  4. 관계: 일대다와 다대다
← C# Academy(으)로 돌아가기