简体   繁体   English

DDD和实体框架,过滤器

[英]DDD and Entity Framework, Filters

So I am struggling with the approach DDD has to follow when we talk about filtering and queries. 因此,当我们谈论过滤和查询时,我正在努力应对DDD必须遵循的方法。 From this SO question Is it okay to bypass the repository pattern for complex queries? 从这个SO问题是否可以绕过复杂查询的存储库模式? I can see the filtering by User should be done after getting all the Products. 我可以看到用户的过滤应该在获得所有产品后完成。 The piece of code from the accepted answer is: 接受的答案中的代码是:

Products products = /* get Products repository implementation */;
IList<Product> res = products.BoughtByUser(User user);

But wait, and if the database has 1 million Products? 但等等,如果数据库有100万个产品? Isn't the best approach to do this filter directly in the database like so: 不是直接在数据库中执行此过滤器的最佳方法,如下所示:

productsRepository.Find(p => p.User.Id == userId);

But from my actual knowledge of DDD this would be wrong, because this logic should be inside the Product itself. 但是根据我对DDD的实际了解,这是错误的,因为这个逻辑应该在产品本身内部。

Therefore, how to handle this scenario? 因此,如何处理这种情况?

I agree with Yorro's answer. 我同意Yorro的回答。 According to the comment, products is indeed a repository. 根据评论,产品确实是一个存储库。 The question around performance of the underlying datastructure vs keeping the domain knowledge in the application could be explored further though. 可以进一步探讨围绕基础数据结构的性能与在应用程序中保持领域知识的问题。 Databases are great at filtering and querying data, they are optimized to do so, and for us to ignore that simply to "keep our knowledge in the domain" is naive. 数据库非常适合过滤和查询数据,它们经过优化可以做到这一点,而我们忽略这一点只是为了“保持我们在域中的知识”是天真的。

Your example shows Repository Specialization, which is fine albeit verbose. 您的示例显示了Repository Specialization,虽然详细,但它很好。 The logic of that search is encapsulated by that call, and as long as the interface for calling that method is in the domain, and the implementation in the data-layer, everything is fine. 该搜索的逻辑由该调用封装,只要用于调用该方法的接口在域中,并且在数据层中实现,一切都很好。 Indeed the call could be to a stored-procedure that performs a very complex operation. 实际上,调用可以是执行非常复杂操作的存储过程。 (In this case, yes some of your logic has escaped the domain, but you make it as a conscious decision, and should you introduce another data technology, you would have to implement that functionality again.) (在这种情况下,是的,你的一些逻辑已经逃脱了域,但你做出了有意识的决定,如果你引入另一种数据技术,你将不得不再次实现该功能。)

There is another option... We can encapsulate the logic of the search in a Specification ( http://en.wikipedia.org/wiki/Specification_pattern ) and pass the specification from our domain logic code to our Repository who would interpret the specification and do the query. 还有另一种选择......我们可以在规范( http://en.wikipedia.org/wiki/Specification_pattern )中封装搜索逻辑,并将规范从我们的域逻辑代码传递给我们的存储库,它将解释规范并进行查询。 That makes our domain oblivious of how the underlying data structure works, but it puts it in control of what the search criteria is. 这使得我们的域名无视基础数据结构的工作方式,但它使其能够控制搜索条件。

I usually find myself implementing a blend of Repository Specialization, and having a base repository that accepts an ISpecification for more lightweight queries. 我通常发现自己实现了Repository Specialization的混合,并且拥有一个基础存储库,可以接受更轻量级查询的ISpecification。

Based on your link, the Products class is the repository, just named without the "repository" suffix. 根据您的链接, Products存储库,只是在没有“repository”后缀的情况下命名。

You are correct that the filtering should be in the database, you just don't see it because you are in the domain. 您是正确的,过滤应该在数据库中,您只是因为您在域中而看不到它。

The first and second approach are the same. 第一种和第二种方法是相同的。 The difference is that the first is more align with DDD because of the proper usage of the ubiquitous language 不同之处在于,由于ubiquitous language的正确使用,第一个更符合DDD

// 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);

If you dive in the data access layer, you can see the filtering that you are talking about. 如果您深入数据访问层,您可以看到您正在谈论的过滤。

public IList<Product> BoughByUser(User user)
{
    IList<Product> products = this.dbContext.Products.Find(p => p.User.Id == user.ID);

    return products;
}

This is not the direct answer of your question (Yorro's answer is right) but maybe it helps you to better understand DDD. 这不是你问题的直接答案(Yorro的答案是正确的)但也许它可以帮助你更好地理解DDD。 This is a "wrong way, turn back" answer. 这是一种“错误的方式,转回”的答案。

Your views doesn't need domain rules; 您的观点不需要域规则; doesn't need aggregates with 1 million of childs or 1 million of entities. 不需要与100万儿童或100万实体的聚合。 So, you don't need to "bypass" the product repository because you should have "View Services" with "View Repositories" wich allows you to query (and paging, etc) denormalize data from persistence for your views. 因此,您不需要“绕过”产品存储库,因为您应该拥有带有“View Repositories”的“View Services”,它允许您从视图的持久性中查询(和分页等)非规范化数据。

You should apply domain rules using aggregates/entities when update/insert/delete is needed. 当需要更新/插入/删除时,您应该使用聚合/实体应用域规则。

Once the user select one or several products from the 1 million list and push, for example, delete button you should use product repository to retrieve the aggregate/entity of selected products, apply delete rules and invariants and save in persistence. 一旦用户从100万个列表中选择一个或多个产品并推送(例如)删除按钮,您应该使用产品存储库来检索所选产品的聚合/实体,应用删除规则和不变量并保存持久性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM