ORM 레이어 위에 추상화 레이어 만들기


12

리포지토리가 있으면 데이터베이스에서 이미 추상화 된 ORM을 사용한다고 생각합니다.

그러나 내가 지금 일하고있는 곳에서 누군가 ORM을 나중에 변경하고 싶다면 ORM을 추상화하는 레이어가 있어야한다고 생각합니다.

많은 ORM에서 작동하는 레이어를 만드는 것이 정말로 필요합니까 아니면 단순히 오버 헤드입니까?

편집하다

더 자세히 설명하면 다음과 같습니다.

  1. AutoMapper로 매핑 된 POCO 클래스와 엔티티 클래스가 있습니다. 엔티티 클래스는 리포지토리 계층에서 사용됩니다. 그런 다음 리포지토리 계층은 추가 추상화 계층을 사용하여 Entity Framework와 통신합니다.
  2. 비즈니스 계층은 Entity Framework에 직접 액세스 할 수 없습니다. ORM에 대한 추가 추상화 계층이 없어도 저장소 계층을 사용하는 서비스 계층을 사용해야합니다. 두 경우 모두 비즈니스 계층은 ORM과 완전히 분리됩니다.
  3. 주요 논점은 미래에 ORM을 바꿀 수 있다는 것입니다. 그것이 실제로 Repository 계층에 국한되어 있기 때문에, 그것은 이미 잘 분리되어 있으며 왜 "품질"코드를 갖기 위해 추가 추상화 계층이 필요한지 알 수 없습니다.

3
여분의 레이어는 정당성을 요구하며, 그렇지 않으면 YAGNI를 위반합니다. 다시 말해, 당신이 그것을 필요로한다고 믿는 누군가 는 그것을 증명할 책임이 있습니다.
gnat

2
원하는 작업 하위 집합 만 노출하는 도메인 계층이 필요하다는 것을 이해할 수 있습니다. ORM은 표면적이 너무 넓은 경향이 있습니다 (예 : 다른 포함 엔티티가 지시하지 않은 엔티티에 대한 업데이트를 허용하지 않으려는 경우). 이러한 추상화 계층을 갖는 것이 도움이됩니다.
Oded

4
첫 번째 레이어도 변경하려는 경우를 대비하여 ORM 위의 첫 번째 추상화 계층에 대한 두 번째 추상화 계층이 필요할 것입니다.
David Peterman

1
@David 리던던시를 추가하는 동안 모든 if (boolean)을 if (boolean == true)로 변경하고 더 많은 것을 동일하게 반복하려면 (boolean == true == true ...) 등
브라이언

답변:


12

그 방법은 광기입니다. ORM을 변경해야 할 가능성은 거의 없습니다. ORM을 변경하기로 결정한 경우 매핑을 다시 작성하는 비용은 자체 메타 ORM을 개발하고 유지 관리하는 데 드는 비용의 작은 부분이됩니다. ORM을 전환하는 데 필요한 작업의 95 %를 수행하기 위해 몇 가지 스크립트를 작성할 수있을 것으로 기대합니다.

사내 프레임 워크는 거의 항상 재난입니다. 미래의 요구를 예상하여 하나를 구축하는 것은 거의 보장 된 재앙입니다. 성공적인 프레임 워크는 성공적인 프로젝트에서 추출되며 가상의 요구를 충족시키기 위해 미리 구축되지 않습니다.


12

ORM은 데이터 계층이 RDBMS와 독립적이되도록 추상화를 제공하지만 비즈니스 계층을 데이터 계층에서 "풀어 내기"에 충분하지 않을 수 있습니다. 특히, RDBMS 테이블에 맵핑되는 오브젝트가 비즈니스 계층으로 직접 "누설"되도록해서는 안됩니다.

최소한 비즈니스 계층은 데이터 계층의 ORM 관리 테이블 매핑 개체가 잠재적으로 구현할 수있는 인터페이스로 프로그래밍해야합니다. 또한 ORM의 기본 조회 기능을 숨기려면 인터페이스 기반의 추상 조회 작성 계층을 작성해야 할 수도 있습니다. 주요 목표는 데이터 계층 이외의 솔루션에 특정 ORM을 "베이크 인"하는 것을 피하는 것입니다. 예를 들어 비즈니스 계층에서 HQL ( Hibernate Query Language ) 문자열 을 작성하려고 할 수 있습니다 . 그러나 이처럼 결백 한 결정은 비즈니스 계층을 최대 절전 모드에 연결하여 비즈니스와 데이터 액세스 계층을 함께 묶을 수 있습니다. 이 상황을 최대한 피하도록 노력해야합니다.

편집 : 귀하의 경우 저장소 내부의 추가 계층은 시간 낭비입니다. 포인트 2를 기준으로 비즈니스 계층이 저장소와 충분히 격리되어 있습니다. 추가적인 단열재를 제공하면 추가적인 이점없이 불필요한 복잡성을 초래할 수 있습니다.

저장소 내에 추가 추상화 계층을 빌드 할 때의 문제점은 ORM의 특정 "브랜드"가 사용자와 상호 작용하는 방식을 결정한다는 것입니다. ORM처럼 보이지만 제어 할 수있는 얇은 랩퍼를 작성하는 경우 기본 ORM을 교체하는 것은 추가 계층이없는 것처럼 어렵습니다. 반면에 ORM처럼 보이지 않는 레이어를 구축하는 경우 객체 관계형 매핑 기술의 선택에 의문을 제기해야합니다.


.NET이 Query Object를 플랫폼에 베이킹하여이 문제를 해결하게되어 매우 기쁩니다. Hibernate의 .NET 포트는 그것을 지원합니다.
Michael Brown

2
@MikeBrown 예, .NET은 LINQ 기술을 사용하여 두 개의 경쟁 ORM 기술을 자체적으로 제공했습니다!
dasblinkenlight

@dasblinkenlight 추가 정보를 제공하기 위해 질문을 업데이트했습니다.
Patrick Desjardins

최근에는 비즈니스 계층이 상태를 저장하기 위해 맵 및 인터페이스와 같은 인터페이스를 기반으로 데이터 계층에 의존하도록하는 접근 방식을 채택했습니다. 이제는 이러한 인터페이스가 상태 유지 문제를 충분히 나타내고 (기능적 프로그래밍 스타일에서 영감을 얻음) 다소 얇은 구현을 통해 선택한 ORM과 멋진 분리를 제공한다고 생각합니다.
beluchin

2

UnitOfWork는 일반적으로이 추상화를 제공합니다. 변경해야 할 한 곳이며, 저장소는 인터페이스를 통해 변경됩니다. O / RM을 변경해야하는 경우 새로운 UoW를 구현하십시오. 하나와 완료.

BTW는 단순히 O / RM을 전환하는 것 이상입니다. 단위 테스트를 생각해보십시오. 세 가지 UnitOfWork 구현이 있습니다. 하나는 EF, 하나는 NH (실제로 DID는 Oracle 지원을 원하는 클라이언트를 위해 프로젝트 중간에 O / RM을 전환해야하기 때문)와 InMemory 지속성을위한 것입니다. InMemory 지속성은 데이터베이스를 배치 할 준비가되기 전에 단위 테스트 나 빠른 프로토 타이핑에 완벽했습니다.

프레임 워크는 구현이 간단합니다. 먼저 일반적인 IRepository 인터페이스가 있습니다

public interface IRepository<T>
  where T:class
{
  IQueryable<T> FindBy(Expression<Func<T,Bool>>filter);
  IQueryable<T> GetAll();
  T FindSingle(Expression<Func<T,Bool>> filter);
  void Add(T item);
  void Remove(T item);

}

그리고 IUnitOfWork 인터페이스

public interface IUnitOfWork
{
   IQueryable<T> GetSet<T>();
   void Save();
   void Add<T>(T item) where T:class;
   void Remove<T>(T item) where T:class;
}

다음은 기본 저장소입니다 (추상적인지 여부에 대한 선택).

public abstract class RepositoryBase<T>:IRepository<T>
  where T:class
{
   protected readonly IUnitOfWork _uow;

   protected RepositoryBase(IUnitOfWork uow)
   { 
      _uow=uow;
   }

   public IQueryable<T> FindBy(Expression<Func<T,Bool>>filter)
   {
      return _uow.GetSet<T>().Where(filter);
   }

   public IQueryable<T> GetAll()
   {
      return _uow.GetSet<T>();
   }

   public T FindSingle(Expression<Func<T,Bool>> filter)
   {
      return _uow.GetSet<T>().SingleOrDefault(filter);
   }

   public void Add(T item)
   {
      return _uow.Add(item);
   }

   public void Remove(T item)
   {
      return _uow.Remove(item);
   }
}

IUnitOfWork 구현은 EF, NH 및 In Memory에 대한 어린이의 놀이입니다. 내가 IQueryable을 반환하는 이유는 Ayende가 그의 게시물에서 언급 한 것과 같은 이유로 클라이언트가 LINQ를 사용하여 결과를 추가로 필터링, 정렬, 그룹화 및 투영 할 수 있으며 서버 측에서 수행되는 모든 이점을 얻을 수 있습니다.


1
그러나 여기서 질문은 위의 계층이 유용하고 모든 데이터 액세스의 게이트 키퍼가되어야하는지 여부를 결정하는 것입니다.
brian

작업 단위 / 저장소 구현에 대한 내 블로그 게시물을 가리킬 수 있기를 바랍니다. OP의 정확한 우려 사항에 대해 설명합니다.
Michael Brown

레이어에 이름을 부여한다고해서 반드시 필요하거나 유용하지는 않습니다.
kevin cline

OP에 따르면 데이터 액세스와 비즈니스 계층간에 추가 매핑이 있습니다. 저에게는 비즈니스 객체와 엔티티 객체가 동일합니다. EF와 NH는 데이터 매핑이 거의 문제가되지 않도록 놀라운 매핑 API를 제공합니다.
Michael Brown

임의의 Expression을 효율적인 ORM 호출로 어떻게 변환합니까? 모든 것을 가져 와서 필터와 일치하지 않는 행을 버릴 수는 없습니다.
케빈 클라인
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.