C# 아키텍처 마스터리 — 클린 아키텍처에서 EF Core (파트 8)

발행: (2025년 12월 24일 오전 06:01 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

Clean Architecture에서 EF Core의 역할

  • EF Core가 무엇인가

    • 영속성 메커니즘
    • 데이터 매핑 도구
    • 인프라스트럭처 관점
  • EF Core가 아닌 것

    • 도메인 모델
    • 비즈니스 규칙 엔진
    • 아키텍처 기반

EF Core가 내부로 새어나가면 Clean Architecture가 무너진다.

EF Core가 위치하는 곳

Infrastructure
 └─ Persistence
     ├─ DbContext
     ├─ EntityConfigurations
     └─ Repositories

DomainApplication 레이어는 절대 다음을 참조해서는 안 된다:

  • DbContext
  • DbSet
  • EF Core 어트리뷰트
  • EF Core LINQ 확장

엄격한 경계: DbContext 누수 금지

// ❌ DbContext leaking inward
class CreateOrderUseCase
{
    private readonly AppDbContext _db;
}

결과

  • 강한 결합
  • 영속성을 인식한 비즈니스 로직
  • 테스트 불가능한 Use Case

인터페이스에 의존하고 EF Core에 의존하지 말 것

public interface IOrderRepository
{
    Task SaveAsync(Order order);
    Task GetByIdAsync(OrderId id);
}

인프라스트럭처 구현

class EfOrderRepository : IOrderRepository
{
    private readonly AppDbContext _db;

    public async Task SaveAsync(Order order)
    {
        _db.Orders.Add(order);
        await _db.SaveChangesAsync();
    }
}

EF Core는 리포지토리 추상화 뒤에 격리된다.

시니어 가이드라인: 도메인이 EF Core를 주도하도록

  • 피해야 할 것

    • EF 전용으로 만든 빈약한 엔티티
    • 어디에든 공개 세터
    • 영속성에 의존하는 불변 조건
  • 선호할 것

    • 풍부한 도메인 모델
    • 캡슐화
    • 명시적인 불변 조건

EF Core는 private 필드와 생성자를 매핑할 수 있다.

흔한 실수: IQueryable을 위쪽으로 누출

// ❌ IQueryable leaking upward
IQueryable Orders { get; }

위험한 이유

  • 로직이 EF 쿼리 변환에 결합됨
  • 추상화 깨짐
  • 비즈니스 규칙이 쿼리 안으로 들어감

올바른 접근법

  • LINQ는 리포지토리 내부에 두기
  • 도메인 객체 또는 DTO 반환

EF Core가 적합하지 않은 시나리오

  • 복잡한 보고서 쿼리
  • 고성능 읽기 모델
  • 대량 작업
  • 무거운 분석

시니어 팀은 보통 다음을 조합한다:

  • EF Core → 쓰기와 애그리게이트
  • Dapper / raw SQL → 읽기

이 하이브리드 접근은 전혀 문제되지 않는다.

EF Core가 잘 다루는 영역

  • 마이그레이션
  • 변경 추적
  • 트랜잭션

하지만 Unit of Work 개념은 애플리케이션 레이어에 속한다:

public interface IUnitOfWork
{
    Task CommitAsync();
}

EF Core는 구현을 제공하지만 추상화는 정의하지 않는다.

테스트 가이드라인

  • Do: 실제 프로바이더를 사용한 통합 테스트 작성; 매핑과 제약 조건을 검증.
  • Avoid: DbContext를 목(mock)하거나 로직 테스트에 InMemory 프로바이더를 과도하게 사용하는 것.

EF Core를 테스트하기 어렵다면 경계가 잘못 잡힌 것이다.

경고 신호 (경계 위반)

  • DbContext가 컨트롤러나 도메인 서비스에 주입됨
  • 도메인 엔티티에 EF 어트리뷰트가 붙어 있음
  • LINQ 쿼리 안에 비즈니스 규칙이 포함됨
  • Lazy loading에 과도하게 의존함

각각의 냄새는 아키텍처 경계가 깨졌음을 나타낸다.

요약

  • 올바른 사용: EF Core는 추상화 뒤에 숨겨지고, 도메인을 지원하며, 교체 가능해야 한다.
  • 잘못된 사용: EF Core가 시스템이 되고, 설계를 좌우하며, 진화를 방해한다.

Clean Architecture에서 EF Core는 도메인을 섬겨야 하며, 절대 도메인을 지배해서는 안 된다.

Written by Cristian Sifuentes — helping teams tame EF Core so architecture stays clean, testable, and resilient.

Back to Blog

관련 글

더 보기 »