数据过滤是否发生在控制器,服务或存储库层中?

Bre*_*ogt 8 c# asp.net-mvc repository entity-framework-4.1 asp.net-mvc-3

我在用ASP.NET MVC 3.我按以下顺序获取我的视图数据:

Controller -> Service Layer -> Repository
Run Code Online (Sandbox Code Playgroud)

在我的存储库中,我有一个GetAll方法,它可以返回特定对象的所有记录,例如Category.

因此,如果我需要所有类别的列表,那么在我的控制器中我会有类似的东西:

IEnumerable<Category> categories = categoryService.GetAll();
Run Code Online (Sandbox Code Playgroud)

在服务层我会有类似的东西:

public IEnumerable<Category> GetAll()
{
     return categoryRepository.GetAll();
}
Run Code Online (Sandbox Code Playgroud)

现在我需要知道我在哪里开始过滤数据?它可以在这3层中的任何一层中完成,还是只需要在存储库层中?让我们说我需要所有的父类别.我是否拥有.GetAll.Where(x => x.ParentCategoryId == null);控制器,服务层或存储库层?

在我的控制器中是否有这样的情况:

IEnumerable<Category> categories = categoryService.GetParentCategories();
Run Code Online (Sandbox Code Playgroud)

在我的服务层,我可以:

public IEnumerable<Category> GetParentCategories()
{
     return categoryRepository.GetAll.Where(x => x.ParentCategoryId == null);
}
Run Code Online (Sandbox Code Playgroud)

或者我的服务层必须如下所示:

public IEnumerable<Category> GetParentCategories()
{
     return categoryRepository.GetParentCategories();
}
Run Code Online (Sandbox Code Playgroud)

然后在我的存储库层中,像这样:

public IEnumerable<Category> GetParentCategories()
{
     return GetAll()
          .Where(x => x.ParentCategoryId == null);
}
Run Code Online (Sandbox Code Playgroud)

请有人帮助澄清我的这种困惑.可能有不同的情况.我可能会带回所有具有活动状态的类别.我可能会带回非活动状态的类别.那我每个都需要一个方法吗?

Joã*_*elo 6

您应该尽可能从数据源中进行过滤,否则,您将检索记录到上层,这些上层由于过滤选项而将被丢弃。这不能很好地扩展,因此您需要在需要过滤的所有层上公开过滤功能,但要确保实际过滤是在最低层进行的,通常是在数据库级别执行的。

在您发布的示例中,如果使用use GetAll返回IEnumerable所有记录中的一个,然后才应用过滤,则将来会遇到问题,因为您基本上是将整个表加载到内存中,然后才应用过滤。

由于您使用的是EF,因此可以利用的延迟执行属性IQueryable。校验:

.NET实体框架-IEnumerableVS。可查询

存储库应该返回IEnumerable,IQueryable还是List?


更新:在评论之后,您还应该检查:

实体的LINQ与对象的LINQ-它们相同吗?


jga*_*fin 5

您应该始终尝试从数据库中获取尽可能少的数据。因此,您应该在存储库类中进行所有过滤。

\n\n

许多文章建议您创建和使用通用存储库。但恕我直言,当您的应用程序增长时,它们不会很好地工作。我建议您使用适当的搜索方法创建适当的存储库类,例如:

\n\n
emailRepository.GetForUser("Ada");\nuserRepository.GetNewUsers();\n
Run Code Online (Sandbox Code Playgroud)\n\n

首先,您隐藏实现细节,例如如何识别新用户。与使用通用查询相比,它还使代码更易于理解和扩展。

\n\n

您还可以添加一些过滤选项:

\n\n
emailRepository.GetForUser("Ada", Filtering.New().Paged(1, 20).SortedBy("FirstName"));\n
Run Code Online (Sandbox Code Playgroud)\n\n

与 @Jo\xc3\xa3oAngelo 不同,我不建议您IQueryable在存储库之外使用。通过这样做,您将把数据库执行移至存储库类之外。这意味着您的存储库无法处理任何错误。

\n