如果数据本质上是分层的,就像某种树结构一样.例如:
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; } }
如果我试图在工厂里修建孩子,那么我需要再次访问这个回购站.如果我在回购中做到这一点,我觉得我正在做工作,应该是工厂.不知道如何解决这个问题.
有一个想法是,Foo不是聚合根,而是FooTree是总根.所以试图获得任何Foo,我需要创建整个树,这意味着我可以将Foo对象的集合传递到FooTreeFactory.
任何帮助将非常感激.
解决方法
当构建这样的层次结构时,您需要确保只打数据库一次.例如,如果您在一次调用db中获取Foo foo1,然后使用相同的存储库方法repo.Get(foo1.Id)获取foo1的子项,那么您将为每个子级添加一个额外的db往返. ..然后一些更多,如果你递归地为每个孩子也.您不希望这样做,因为这将导致未知数量的额外的数据库往返(select N+1 problem的变体).
你想要的是一个在一个数据库往返中获取完整层次结构的存储库.如果您正在使用ORM,那么通常ORM有一些内置的东西来处理这个;例如NHibernate has a DistinctRootEntityResultTransformer
这样做.
如果要使用plain-sql存储库,那么我将创建一个存储过程(假设您正在使用sql Server)从数据库中循环获取层次结构中的所有Foo行,并将它们返回到存储库.存储库然后将此结果集传递到工厂以创建对象树.
所以关键是不要将单个Foo传递给您的工厂,而是将阅读器传递给读取Foo行结果集的工厂,而不是单行.
更新
重读了你的问题后,我想你和@enrico都是:
[…] the
FooTree
is the aggregate root. So trying to get anyFoo
I would
need to create the entire tree,which means I could pass a collection
ofFoo
objects to aFooTreeFactory