Как использовать общий репозиторий с DDD (модель домена + модель сохраняемости)?

У меня есть вопрос. мы используем общий репозиторий, и наша модель предметной области также является моделью персистентности, но это заставило нас сильно настроить нашу модель предметной области, чтобы она была согласована с ORM, например: - Мы должны поместить частный конструктор по умолчанию и некоторые другие грязные изменений, мы используем (в данном случае Entity Framework), и теперь мы решили использовать модель сохранения, которая отличается от нашей модели расширенной предметной области, но мы не можем использовать общий репозиторий в этом случае. Примечание. - Мы используем фабрики для создания моделей предметной области, но мы используем AutoMapper для преобразования моделей предметной области в модель сохраняемости.


person roro2012    schedule 14.11.2016    source источник
comment
мы не можем использовать общий репозиторий в этом случае - почему? И зачем вам это вообще нужно?   -  person guillaume31    schedule 14.11.2016
comment
Привет, мне это нужно для упрощения процесса разработки   -  person roro2012    schedule 14.11.2016
comment
Мне не нужно повторять один и тот же код в каждом репозитории   -  person roro2012    schedule 14.11.2016
comment
Какой код вы не хотите повторять, как этого добиться и почему он несовместим с моделью персистентности? Также посмотрите blog.sapiensworks.com/post/2012/03/05/   -  person guillaume31    schedule 14.11.2016
comment
Например, общие запросы, которые принимают предикаты   -  person roro2012    schedule 14.11.2016
comment
Я имею в виду, что когда я использую Generic Repository, большая часть кода находится в Generic репозитории, например, Add / Update / Delete / Read, и многие общие запросы   -  person roro2012    schedule 14.11.2016
comment
В универсальном репозитории я зависим от TEntity, но в случае наличия модели сохраняемости и модели домена я не могу зависеть от TEntity, поскольку каждый агрегат будет иметь разные фабрики или консткуторы.   -  person roro2012    schedule 14.11.2016
comment
Entity Framework - это репозиторий, зачем строить на нем еще один?   -  person L-Four    schedule 15.11.2016
comment
Какой вопрос?   -  person Gert Arnold    schedule 15.11.2016


Ответы (1)


Это сложный вопрос, потому что вы пытаетесь примирить два антагонистических подхода к настойчивости в DDD, которые были разработаны противоположными школами.

Шаблон Generic Repository, который некоторые считают antipattern, восходит к раннему принятию DDD, когда люди искали инструменты и методы для упрощения персистентности в системах DDD. Большинство реализаций в конечном итоге раскрывают особенности запросов ORM (IQueryable в случае Entity Framework) в контракте общего репозитория, потому что они были удобной точкой соприкосновения между всевозможными вещами, которые вы могли запросить в репо.

Более поздний подход модели персистентности - это шаг в противоположном направлении - от ORM. Что вы делаете, так это вводите дополнительный уровень косвенности, чтобы оставить вашу модель предметной области (которая также включает интерфейсы репозитория) незапятнанной специфическими вещами уровня сохраняемости.

Если вы по-прежнему абсолютно уверены, что общий репозиторий - это лучший компромисс для вас с точки зрения выгоды от повторного использования кода (что я бы рекомендовал в первую очередь оспорить), Грег Янг дает нам разумную золотую середину:

Итак, ответ здесь - по-прежнему использовать общий репозиторий, но использовать композицию вместо наследования и не предоставлять его домену в качестве контракта.

Вы можете использовать тот же подход и воспользоваться этим швом, чтобы добавить в микс отображение модели предметной области / модели персистентности.

Возможно, что-то в этом роде (не проверено):

public class FooRepository
{
    private PersistenceRepository<FooPersistence> _innerRepository;

    public Foo GetFooById(int id)
    {
        return MapToDomain(_innerRepository.GetById(id));
    }

    public void Add(Foo foo)
    {
        _innerRepository.Add(MapToPersistence(foo));
    }

    public IEnumerable<Foo> GetByCity(string city)
    {
        return _innerRepository.Find(f => f.City == city).Select(MapToDomain);
    }

    private Foo MapToDomain(FooPersistence persistenceModel)
    {
        // Mapping stuff here
    }

    private FooPersistence MapToPersistence(Foo foo)
    {
        // Mapping stuff here
    }
}

public class PersistenceRepository<T> where T : PersistenceModel
{
    public T GetById(int id)
    {
        //...
    }

    public void Add(T t)
    {
        //...
    }

    public IQueryable<T> Find(Func<T, bool> predicate)
    {
        //...
    }
}

public abstract class PersistenceModel
{
}

public class FooPersistence : PersistenceModel
{
    public string City { get; set; }
}
person guillaume31    schedule 15.11.2016
comment
Спасибо за отличное решение - person roro2012; 17.11.2016
comment
У меня другая проблема. Как использовать шаблон спецификации по-новому - person roro2012; 17.11.2016
comment
обратите внимание: спецификации - это поведение модели предметной области, а не постоянство - person roro2012; 17.11.2016
comment
Думаю, вам понадобится преобразователь от Func<Foo, bool> к Func<FooPersistence, bool>. - person guillaume31; 17.11.2016
comment
Не могли бы вы пояснить на примере, пожалуйста? - person roro2012; 17.11.2016
comment
Каковы ваши намерения? Find(FooSpecification spec) метод, который вызывает Find(FooPersistenceSpecification(spec) во внутреннем репо? - person guillaume31; 17.11.2016
comment
Привет! Это одна из моих спецификаций. Спецификация ‹Country› спецификация = новая спецификация DirectSpecification ‹Country› (c = ›c.Name.ToLower (). Contains (text.ToLower ())); - person roro2012; 17.11.2016
comment
а старый Repos принимает спецификацию IS и вызывает его метод SatisfiedBy - person roro2012; 17.11.2016
comment
Если вы хотите, чтобы все было так, вам нужно что-то, что, по сути, может отображать Specification<Foo> в Specification<FooPersistence>. Это возможно, если проанализировать предикат или унаследовать модель предметной области и модель персистентности от одного и того же класса. В этот момент все становится довольно запутанным. Лучше избегать общих спецификаций в репозиториях домена и оставить их к внутреннему постоянному репо ИМО. - person guillaume31; 18.11.2016