public class Product: Entity { public IList<Item> Items { get; set; } }
假设我想要找到一个最大的东西的项目…我可以添加方法Product.GetMaxItemSmth(),并使用Linq(从我在项目选择i.smth).Max())或手动循环或任何.现在,问题是这将把完整的集合加载到内存中.
正确的解决方案是做一个特定的DB查询,但是域实体不能访问存储库,对吧?所以我要么
productRepository.GetMaxItemSmth(product)
(这是丑,不?),或者即使实体访问存储库,我使用IProductRepository从实体
product.GetMaxItemSmth() { return Service.GetRepository<IProductRepository>().GetMaxItemSmth(); }
这也是丑陋的,是代码的重复.我甚至可以去花哨,做一个延伸
public static IList<Item> GetMaxItemSmth(this Product product) { return Service.GetRepository<IProductRepository>().GetMaxItemSmth(); }
这只是因为它不会真正地使实体与仓库混淆,而是仍然进行方法重复.
现在,这是否再次使用product.GetMaxItemSmth()或productRepository.GetMaxItemSmth(product)…的问题.我想念DDD吗?这里有什么正确的方法?只需使用productRepository.GetMaxItemSmth(product)?这是每个人都使用和快乐吗?
我只是不觉得是正确的…如果我无法从产品本身访问产品的项目,为什么我需要在产品中的这个集合?然后,如果产品无法使用特定查询并且无需使用性能匹配则访问其集合,产品可以做任何有用的事情?
当然,我可以使用一种效率较低的方式,而不用介意,当它慢的时候,我将把存储库调用注入实体作为一个优化,但即使这听起来不对,是吗?
有一点要提到,也许它不是DDD …但是我需要IList在产品中,以获得我的数据库模式生成与Fluent NHibernate.尽管在纯DDD环境中随意回答.
更新:一个非常有趣的选择在这里描述:http://devlicio.us/blogs/billy_mccafferty/archive/2007/12/03/custom-collections-with-nhibernate-part-i-the-basics.aspx,不仅处理与DB相关的集合查询,还可以帮助收集访问控制.
解决方法
为了纯粹,您的实体不应该直接访问存储库.但是,它们可以通过查询规范进行间接引用.查看埃里克·埃文斯的书的第229页.这样的事情
public class Product { public IList<Item> Items {get;} public int GetMaxItemSmth() { return new ProductItemQuerySpecifications().GetMaxSomething(this); } } public class ProductItemQuerySpecifications() { public int GetMaxSomething(product) { var respository = MyContainer.Resolve<IProductRespository>(); return respository.GetMaxSomething(product); } }
您如何获取对存储库的引用是您的选择(DI,服务定位器等).虽然这样会删除了Entity和Respository之间的直接引用,但它并没有减少LoC.