所以当我们谈论过滤和查询时,我正在努力解决DDD必须遵循的方法。从这个问题Is it okay to bypass the repository pattern for complex queries?我可以看到用户的过滤应该在获得所有产品后完成。接受的答案中的代码是:
Products products = /* get Products repository implementation */;
IList<Product> res = products.BoughtByUser(User user);
但等等,如果数据库有100万个产品?这不是直接在数据库中执行此过滤器的最佳方法,如下所示:
productsRepository.Find(p => p.User.Id == userId);
但是根据我对DDD的实际了解,这是错误的,因为这个逻辑应该在产品本身内部。
因此,如何处理这种情况?
答案 0 :(得分:4)
我同意Yorro的回答。根据评论,产品确实是一个存储库。 可以进一步探讨围绕基础数据结构的性能与在应用程序中保持领域知识的问题。 数据库非常适合过滤和查询数据,它们已经过优化,我们可以忽略这些,只是为了保持我们在域中的知识。很天真。
您的示例显示了Repository Specialization,虽然详细,但这很好。 该搜索的逻辑由该调用封装,只要用于调用该方法的接口在域中,并且在数据层中实现,一切都很好。 实际上,调用可以是执行非常复杂操作的存储过程。 (在这种情况下,是的,你的一些逻辑已经逃脱了域,但你做出了有意识的决定,如果你引入另一种数据技术,你将不得不再次实现该功能。)
还有另一种选择...... 我们可以在规范(http://en.wikipedia.org/wiki/Specification_pattern)中封装搜索的逻辑,并将规范从我们的域逻辑代码传递给我们的Repository,后者将解释规范并执行查询。 这使得我们的域名无视基础数据结构的工作方式,但它使其能够控制搜索条件。
我经常发现自己实现了Repository Specialization的混合,并且拥有一个基础存储库,可以接受更轻量级查询的ISpecification。
答案 1 :(得分:2)
根据您的链接,Products
类是存储库,只是在没有“存储库”后缀的情况下命名。
您是正确的,过滤应该在数据库中,您只是因为您在域中而看不到它。
第一种和第二种方法是相同的。不同之处在于,由于正确使用ubiquitous language
// First example
// Take note, the products IS the repository
IList<Product> productsByUser = products.BoughtByUser(User user);
// Second example
IList<Product> productsByUser = productsRepository.Find(p => p.User.Id == userId);
如果你深入数据访问层,你可以看到你正在谈论的过滤。
public IList<Product> BoughByUser(User user)
{
IList<Product> products = this.dbContext.Products.Find(p => p.User.Id == user.ID);
return products;
}
答案 2 :(得分:1)
这不是你问题的直接答案(Yorro的回答是正确的)但也许它可以帮助你更好地理解DDD。这是一种错误的方式,转回&#34;答案。
您的观点不需要域名规则;不需要与100万儿童或100万实体进行汇总。所以,你不需要绕过&#34;产品存储库,因为您应该拥有&#34;查看服务&#34;使用&#34;查看存储库&#34;这允许您查询(和分页等)从视图的持久性中非正规化数据。
当需要更新/插入/删除时,您应该使用聚合/实体应用域规则。
一旦用户从100万个列表中选择一个或多个产品并推送(例如)删除按钮,您应该使用产品存储库来检索所选产品的聚合/实体,应用删除规则和不变量并保存持久性。 / p>