도메인 개체에서 리포지토리를 사용하거나 도메인 개체를 서비스 계층으로 다시 밀어야합니까?


10

나는 거래 스크립트 세계에서 왔으며 방금 DDD를 살펴보기 시작했습니다. DDD 디자인을 데이터베이스 지속성과 통합하는 올바른 방법이 확실하지 않습니다. 이것이 내가 가진 것입니다 :

인터페이스에 Organization 도메인 객체의 인스턴스를 검색하고 저장하는 메소드가 포함 된 OrganisationService라는 서비스 클래스. 조직은 집계 루트이며 이와 관련된 다른 데이터가 있습니다 (멤버 및 라이센스). EF6 데이터베이스의 첫 번째 DBContext는 OrganisationService 내에서 OrganisationDB 엔티티 및 관련 MemberDB 및 LicenseDB 엔티티를 검색하는 데 사용됩니다. 이들은 모두 OrganisationService에 의해 검색되어 Organization 도메인 객체로로드 될 때 해당 도메인 객체 클래스로 변환됩니다. 이 객체는 다음과 같습니다.

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }
}

OrganisationService에서 Repository 패턴을 사용하고 있지 않습니다 ... EF6가 현재 리포지토리를 대체로 중복시킨 것으로 보이므로 EF 자체를 리포지토리로 사용하고 있습니다.

디자인의 현재 시점에서 조직 도메인 개체는 혐의입니다. EF POCO Organization 클래스처럼 보입니다. OrganisationService 클래스는 리포지토리와 매우 비슷합니다!

이제 논리 추가를 시작해야합니다. 이 논리에는 조직 라이센스 및 멤버 관리가 포함됩니다. 이제 트랜잭션 스크립트 일에 이러한 작업을 처리하기 위해 OrganisationService에 메소드를 추가하고 DB와 상호 작용하기 위해 리포지토리를 호출하지만 DDD를 사용하면이 논리가 조직 도메인 객체 자체 내에 캡슐화되어야한다고 생각합니다 ...

여기에서 내가 무엇을해야할지 잘 모르겠습니다.이 데이터를 논리의 일부로 데이터베이스에 다시 유지해야합니다. 이것이 조직 도메인 개체 내에서 DbContext를 사용해야한다는 의미입니까? 도메인 개체 내에서 리포지토리 / EF를 사용하는 것이 좋지 않습니까? 그렇다면이 지속성은 어디에 속합니까?

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }

    public void AddLicensesToOrganisation(IList<License> licensesToAdd)
    {
        // Do validation/other stuff/

        // And now Save to the DB???
        using(var context = new EFContext())
        {
            context.Licenses.Add(...
        }

        // Add to the Licenses collection in Memory
        Licenses.AddRange(licensesToAdd);
    }
}

대신 메모리에서 조직 도메인 개체를 변경 한 다음 지속성을 위해 다시 조직 서비스로 푸시해야합니까? 그런 다음 객체에서 실제로 변경된 사항을 추적해야합니다 (EF가 자체 POCO에 수행하는 작업입니다! EF가 저장소 교체가 아니라 도메인 계층이 될 수 있음을 느끼게됩니다!)

여기에 모든 지침을 부탁드립니다.

답변:


2

두 가지 방법 중 하나를 선택하여 잘 작동시킬 수 있습니다. 물론 장단점이 있습니다.

Entity Framework는 도메인 엔터티를 만족 시키기위한 것 입니다. 도메인 엔터티와 데이터 엔터티가 동일한 클래스 인 경우 잘 작동합니다. EF를 사용하여 변경 사항을 추적하고 context.SaveChanges()트랜잭션 작업이 끝나면 전화를 걸면 훨씬 좋습니다 . 같은 것들 - 또한 수단 유효성 검사 속성은 도메인 모델에 한 번 한 번 지속 엔티티에 두 번 설정하지 않아도 [Required]또는 [StringLength(x)]확인 할 수 있습니다 귀하의 비즈니스 로직에 당신이 시도하기 전에 유효하지 않은 데이터 상태를 잡을 수 있도록, DB 트랜잭션을 수행하고EntityValidationException. 마지막으로, 코딩이 빠릅니다. 매핑 계층이나 리포지토리를 작성할 필요는 없지만 EF 컨텍스트에서 직접 작업 할 수 있습니다. 이미 저장소와 작업 단위이므로 추가 추상화 계층으로 아무것도 달성 할 수 없습니다.

도메인과 지속 된 엔터티를 결합하면 단점은 [NotMapped]속성 전체에 흩어져 있는 여러 가지 속성으로 끝날 수 있다는 것 입니다. 종종 지속 데이터의 가져 오기 전용 필터이거나 나중에 비즈니스 로직에서 설정되고 데이터베이스에 다시 유지되지 않는 도메인 별 특성을 원할 것입니다. 때로는 데이터베이스에서 잘 작동하지 않는 방식으로 도메인 모델로 데이터를 표현 int하고 싶을 수도 있습니다. 사람이 읽을 수 string있도록 데이터베이스를 검사 할 때 조회를 참조 할 필요가 없습니다. 그런 다음 string매핑 된 속성으로 끝납니다 .enum그렇지 않은 속성 (그러나 문자열을 가져 와서 열거 형에 매핑)과 둘 다 노출하는 API! 마찬가지로 컨텍스트간에 복잡한 유형 (테이블)을 결합하려는 경우 mappedOtherTableId 및 매핑되지 않은 ComplexType속성을 사용하여 클래스에 공개로 노출 될 수 있습니다. 이것은 프로젝트에 익숙하지 않은 사람에게는 혼란스럽고 불필요하게 도메인 모델을 부 풀릴 수 있습니다.

비즈니스 로직 / 도메인이 복잡할수록 내 도메인과 지속 된 엔터티를 결합하는 것이 더 제한적이거나 번거 롭습니다. 마감 시간이 짧거나 복잡한 비즈니스 계층을 나타내지 않는 프로젝트의 경우 두 가지 목적으로 EF 엔터티를 사용하는 것이 적절하며 도메인을 지속성에서 벗어나지 않아도됩니다. 최대 확장 용이성이 필요하거나 매우 복잡한 논리를 표현해야하는 프로젝트의 경우 두 가지를 분리하고 추가 지속성 복잡성을 처리하는 것이 좋습니다.

엔티티 변경 사항을 수동으로 추적하는 데 따른 문제점을 피하기위한 한 가지 트릭은 해당 지속 엔티티 ID를 도메인 모델에 저장하는 것입니다. 이것은 매핑 레이어에 의해 자동으로 채워질 수 있습니다. 그런 다음 변경 사항을 EF로 다시 유지해야하는 경우 매핑을 수행 하기 전에 관련 영구 엔터티 검색하십시오 . 그런 다음 변경 사항을 매핑하면 EF가 자동으로 변경 사항을 감지하므로 context.SaveChanges()직접 추적하지 않고도 전화 를 걸 수 있습니다 .

public class OrganisationService
{
    public void PersistLicenses(IList<DomainLicenses> licenses) 
    {
        using (var context = new EFContext()) 
        {
            foreach (DomainLicense license in licenses) 
            {
                var persistedLicense = context.Licenses.Find(pl => pl.Id == license.PersistedId);
                MappingService.Map(persistedLicense, license); //Right-left mapping
                context.Update(persistedLicense);
            }
            context.SaveChanges();
        }
    }
}

다른 접근법을 다른 데이터 복잡도와 결합 할 때 문제가 있습니까? DB에 잘 매핑되는 것이 있으면 EF를 직접 사용하십시오. 그렇지 않은 것이 있으면 EF를 사용하기 전에 매핑 / 추상을 소개하십시오.
Euphoric

@Euphoric 도메인과 db의 차이점은 매핑에서 처리 할 수 ​​있습니다. 도메인을 두 번 추가하고 (영구적이지 않고 영구적이 아닌) 변경 추적을 수동으로 처리하는 것이 특별한 경우에 대한 매핑을 추가하는 것보다 작업이 적은 유스 케이스를 생각할 수 없습니다. 하나만 말씀해 주시겠습니까? (NHibernate를 사용한다고 가정합니다. 아마도 EF가 더 제한적입니까?)
Firo

매우 유용하고 실용적이고 유익한 답변. 답변으로 표시. 감사!
MrLane

3

나는 EF6을 모르지만 다른 ORM은 이것을 투명하게 처리하므로 컨텍스트에 라이센스를 명시 적으로 추가 할 필요가 없으며 변경 사항을 저장할 때 라이센스를 감지합니다. 따라서 방법은

public void AddLicenses(IEnumerable<License> licensesToAdd)
{
    // Do validation/other stuff/
    // Add to the Licenses collection in Memory
    Licenses.AddRange(licensesToAdd);
}

그리고 그 주위의 코드

var someOrg = Load(orgId);

someOrg.AddLicenses(someLicences);

SaveChanges();

내 도메인 개체는 엔터티가 아니므로 라이센스 컬렉션에 추가하면 목록이됩니다. 실제 지속성이 발생하는 곳이기 때문에 EF에 대한 질문은 그리 많지 않습니다. EF의 모든 지속성은 컨텍스트 범위 내에서 이루어져야합니다. 문제는 이것이 어디에 속합니까?
MrLane

2
도메인 엔터티와 지속 엔터티는 동일 할 수 있습니다. 그렇지 않으면 99 %의 시간이 걸리지 않고 변경 내용 추적이 손실되는 다른 추상화 계층을 도입 할 수 있습니다.
Firo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.