2013-12-06 3 views
10

Я занимаюсь разработкой проектов под управлением домена Эриком Эвансом, где он описывает взаимодействие между репозиториями и фабриками. Сам репозиторий вызовет интерфейс БД для получения набора результатов. Этот набор результатов затем будет передан на фабрику, которая будет понимать, что набор результатов воссоздает объект.Хранилища, фабрики и иерархически структурированные данные

Что делать, если данные были иерархическими по своему характеру, вроде какой-то древовидной структуры. Например:

public class Foo 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Foo Parent { get; set; } 
    public ICollection<Foo> { get; set; } 

    // Other business like methods here 

} 

Использование DDD Я бы мои интерфейсы и реализации:

public interface IFooRepository 
{ 
    Foo Get(int id); 
} 

public interface IFooFactory<TSource> 
{ 
    Foo Create(TSource source); 
} 

public class SqlFooRepository: IFooRepository 
{ 
    private readonly IFooDao dao; 
    private readonly IFooFactory<SqlDataReader> factory; 

    public SqlFooRepository(IFooDao dao, IFooFactory factory) 
    { 
     this.dao = dao; 
     this.factory = factory; 
    } 

    public Foo Get(int id) 
    { 
     var resultSet = dao.Find(id); 
     return factory.Create(resultSet); 
    } 
} 

public class SqlFooFactory: IFooFactory<SqlDataReader> 
{ 
    public Foo Get(SqlDataReader reader) 
    { 
     var foo = new Foo(); 
     foo.Id = (int) reader["id]; 
     foo.Name = (string) reader["name"]; 
      // Do I build the children accounts here 
     return foo; 
    } 
} 

Если я пытаюсь построить детей на заводе-изготовителе, то я снова нужен доступ к репо. Если я сделаю это в Repo, я чувствую, что делаю работу, которая должна быть на заводе. Не знаете, как справиться с этим.

Одна мысль, что у меня есть, что Foo не является совокупным корнем, а FooTree является совокупным корнем. Поэтому, пытаясь получить любой Foo, мне нужно будет создать все дерево, а это значит, что я могу передать коллекцию объектов Foo в FooTreeFactory.

Любая помощь будет очень признательна.

+0

Получить метод можно построить Foo и все связанные с детьми, Вы должны загрузить все запрошенные записи из БД в SQL-запросе и в общем виде создают ваше дерево (у вас есть все необходимые данные, например ParentId, ChildId и для создания вашего дерева); Вам не нужно разговаривать здесь с вашими репозиториями или любым другим слоем, кроме бэкэнда! –

+0

Можете ли вы, возможно, разработать и сделать это в форме ответа. Затем я могу отметить вас как принятый ответ, если он лучше всего подходит. – uriDium

ответ

3

Предполагая, что необходимо всем детям при работе с Foo, вы должны забрать их в репозитории и восстановить иерархию на своей фабрике. Если вы не обязательно нуждаетесь в них; или вам могут понадобиться их в некоторых сценариях с короткими случаями, вы можете подумать о том, чтобы их получить лениво, но я полагаю, что это не то, что вы здесь делаете.

При построении такой иерархии вы хотите удостовериться, что только один раз ударил базу данных. Например, если вы выберете Foo foo1 в одном вызове в db, а затем выберете дочерние элементы foo1 с использованием того же метода репозитория repo.Get(foo1.Id), тогда у вас будет дополнительный db roundtrip для каждого ребенка ... а затем еще несколько, если вы это рекурсивно для каждого ребенка.Вы не хотите этого, потому что это приведет к неизвестному количеству дополнительных посещений базы данных (вариант select N+1 problem).

Что вы хотите, это репозиторий, который извлекает вашу полную иерархию в одной базе данных в оба конца. Если вы используете ORM, то часто ORM имеет что-то встроенное для обработки этого для вас; например, NHibernate has a DistinctRootEntityResultTransformer, чтобы сделать именно это.

Если вы хотите это с хранилищем равнинно-SQL, то я бы создать хранимую процедуру (предполагая, что вы используете SQL Server), который извлекает все Foo строки в иерархии рекурсивно из базы данных и возвращает их в одном результирующий набор в репозиторий. Затем репозиторий передает этот результирующий набор на ваш завод для создания дерева объектов.

Так что ключ не пройти один Foo на вашу фабрику, но вместо того, чтобы передать reader на завод, который читает результирующий набор строк Foo, вместо одной строки.

Update

После перечитывания вашего вопроса, я думаю, вы и @enrico пятно на:

[...] FooTree является совокупным корнем. Так пытаюсь получить любую Foo я бы необходимости создать целое дерево, которое означает, что я мог бы передать коллекцию из Foo объектов к FooTreeFactory

2

Do not reference other AggregateRoot when designing Aggregate.

Таким образом, в общем случае, A Foo не будет ссылаться на другие FOOS в виде дерева или родителя. Это может быть требование запроса, если вам это нужно. Например, отображение данных. DDD не подходит для запроса, поэтому его легче реализовать с помощью анемичных моделей без большого количества ограничений и правил DDD.

UPDATE
Вы можете рассмотреть Specification pattern, если это иерархия используется для домена отведениях.

public class FooBarSpecification 
{ 
    public Foo Parent //injected by constructor 
    public ICollection<Foo> //injected by constructor 

    public boolean isSatisfiedBy(Foo foo) { 
     //use FooTree here to 
    } 

} 

Клиент может использовать FooRepository, чтобы получить Foos, чтобы начать спецификацию.

Другое решение использует DomainService.

+0

Но у меня есть некоторые методы в объектах Foo, которые будут вызывать другие методы родительского элемента Foo для выполнения своей работы. Вот почему дерево было необходимо. ОБНОВЛЕНИЕ: В модели очень важен тот факт, что эта связь существует. Как мне моделировать эти отношения? – uriDium

+0

@uriDium Извините, забудьте о случае деривации домена. Ответ обновлен. – Hippoom

4

Хранилища обрабатывают сводные корни, а не сущности. Итак, я предлагаю вам пойти с решением FooTree AR и получить его из db. Завод не должен зависеть от Репозитория, поэтому вам нужно взять все данные дерева и передать их на завод. Кроме того, вы можете реализовать что-то вроде ленивой загрузки ORM и «ленивой загрузки», когда запрашивает их AR-клиент (или сам AR).

+0

+1; спотыкаться и лаконично – Marijn

Смежные вопросы