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

时间:2011-11-25 12:24:58

标签: c# asp.net-mvc asp.net-mvc-3 entity-framework-4.1 repository

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

Controller -> Service Layer -> Repository

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

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

IEnumerable<Category> categories = categoryService.GetAll();

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

public IEnumerable<Category> GetAll()
{
     return categoryRepository.GetAll();
}

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

我的控制器中是否有这样的颜色:

IEnumerable<Category> categories = categoryService.GetParentCategories();

在我的服务层,我可以:

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

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

public IEnumerable<Category> GetParentCategories()
{
     return categoryRepository.GetParentCategories();
}

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

public IEnumerable<Category> GetParentCategories()
{
     return GetAll()
          .Where(x => x.ParentCategoryId == null);
}

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

2 个答案:

答案 0 :(得分:4)

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

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

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

.NET Entity Framework - IEnumerable VS. IQueryable

Should a Repository return IEnumerable , IQueryable or List?


更新:跟进您的评论,您还应该检查:

LINQ to entities vs LINQ to objects - Are they the same?

答案 1 :(得分:2)

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

许多文章都建议您创建和使用通用存储库。但是当你的应用程序增长时,它们将无法正常工作。我建议您使用适当的搜索方法创建正确的存储库类,如:

emailRepository.GetForUser("Ada");
userRepository.GetNewUsers();

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

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

emailRepository.GetForUser("Ada", Filtering.New().Paged(1, 20).SortedBy("FirstName"));

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