내용으로 건너뛰기
Entity Framework 컨텍스트 추상화

Entity Framework 컨텍스트 추상화

프로젝트의 크기, 범위 및 요구 사항에 따라 추가 추상화 또는 캡슐화 없이 Entity Framework와 같은 ORM을 사용하도록 선택했을 수 있습니다. 대기업 애플리케이션에는 복잡한 계층화와 서비스가 필요할 수 있지만 개발 오버헤드는 정당화되어야 합니다.

4min read

프로젝트의 크기, 범위 및 요구 사항에 따라 추가 추상화 또는 캡슐화 없이 Entity Framework와 같은 ORM을 사용하도록 선택했을 수 있습니다. 대기업 애플리케이션에는 복잡한 계층화와 서비스가 필요할 수 있지만 개발 오버헤드는 정당화되어야 합니다.

ORM이 제공하는 데이터 액세스 및 객체 관계형 추상화 외에 더 많은 추상화를 언제 사용해야 하는지에 대해 강의하는 대신, 기존 프로젝트에서 추상화가 필요하게 되는 일반적인 문제를 다루고 싶습니다.

이 문서에서는 주로 Entity Framework를 다루지만 대부분은 다른 ORM에 적용할 수 있습니다. 내 접근 방식은 재 작성을 피하고 코드 영향을 최소화하는 것입니다.

어디에나 있는 저장소

어떤 사람들은 ASP.NET MVC 컨트롤러, MVVM 뷰 모델 또는 발표자에서 EF 컨텍스트를 사용하는 것을 인정하지 않습니다. 포럼이나 컨퍼런스 토론에서 이를 언급하면 특정 은색 총알 패턴인 Repository를 사용하지 않은 것에 대해 부끄러워할 수 있습니다.

그것은 미세한 패턴이며, 당신은 이미 그것을 사용하고 있습니다. 그러나 그 사람이 선호하는 인터페이스(예: IRepository)를 사용하고 있지 않습니다. 일부 버전에서는 엄청난 양의 재작성이 발생합니다. 스프린트 1, 2, 3 "리팩토링"에 오신 것을 환영합니다!

리포지토리 패턴이 나타내는 내용을 고려하여 이 결과를 피하십시오.

"저장소(Repository)는 도메인(domain)과 데이터(data) 매핑 레이어 사이를 중재하며, 인메모리 도메인 객체 컬렉션과 같은 역할을 한다" –EAA 카탈로그의 P

저장소의 호출자는 일종의 컬렉션만 알고 있으며 저장소의 데이터 스토리지에 대해 걱정하지 않아야 합니다. Entity Framework는 데이터 매핑을 처리하며, 리포지토리에는 데이터 양이 비결정적일 가능성이 높으므로 쿼리 조건을 수락할 수 있는 방법이 있어야 합니다.

DbSet은 저장소입니다.

문제는 저장소가 없다는 것이 아닙니다. 콘크리트 커플 링입니다. 대신 컨텍스트 클래스의 DbSet 속성을 IDbSet으로 변경합니다. 컴파일 타임 오류가 있는 경우 System.Data.Entity에 대한 using 절을 포함해야 합니다. 구체적 클래스는 DbQuery에서 파생되지만 대부분의 추가 메서드는 IDbSet에 대한 확장 메서드로도 사용할 수 있습니다. 그것들을 범위로 가져오면 트릭을 수행할 수 있습니다.

Context Interface

MSDN 설명서에서는 DbContext를 리포지토리로 설명합니다. 이것은 정확하지만 응용 프로그램별 컨텍스트는 리포지토리 백과 더 비슷합니다.

public class AppContext : DbContext
{
    public IDbSet<Department> Departments { get; set; }
    public IDbSet<Employee> Employees { get; set; }
    public IDbSet<Person> People { get; set; }
}

파생 클래스는 처리하는 다양한 엔터티 형식에 대한 속성을 정의하고 호출자는 이러한 속성인 context를 사용합니다. 직원은 컨텍스트보다 더 편리하고 읽기 쉽습니다. Set()입니다. 이것은 좋지만 DbContext는 리포지토리 백 그 이상입니다. 이 추상화의 일부는 필요한 부분만 결정하고 정의해야 합니다.

초기 인터페이스는 구체적인 클래스에서 완전히 추출할 수 있습니다. 그러나 DbContext는 작업 단위 패턴도 나타내므로 컨텍스트는 변경 내용을 저장하고 취소하는 역할도 담당합니다. 데이터 저장은 명시적 메서드 호출을 사용하며, 호출되지 않은 경우 삭제 가능한 패턴을 사용하여 변경 사항을 취소합니다.

 public interface IAppContext : IDisposable
 {
      IDbSet<Department> Departments { get; set; }
      IDbSet<Employee> Employees { get; set; }
      IDbSet<Person> People { get; set; }
      int SaveChanges();
      Task<int> SaveChangesAsync();
 }
  
public class AppContext : DbContext, IAppContext
{
     public IDbSet<Department> Departments { get; set; }
     public IDbSet<Employee> Employees { get; set; }
     public IDbSet<Person> People { get; set; }
}

AppContext의 명시적 선언을 IAppContext로 바꾸면 DbContext 종속성이 노출됩니다. 깨끗한 빌드와 종속성 기록을 위해 누락된 부분을 인터페이스에 추가합니다.

다음 단계

이 인터페이스 추출의 첫 번째 비트는 재미있었지만 다양한 객체 지향 디자인 패턴을 사용하는 솔루션에 유연성을 제공하기도 합니다. 다음 기사에서 가장 중요한 작업인 구체적인 컨텍스트 종속성 제거에 대해 다룰 것입니다.

데모 요청