使用存储库时,在ASP.NET MVC中,业务逻辑的最佳位置是什么?

14

在ASP.NET MVC项目中实现数据库Repository时,将业务逻辑放入其中是正确的吗?还是将逻辑放入控制器类中更好?或者使用其他服务和辅助类来操作数据?

5个回答

14

在业务逻辑方面,最好的选择是将其置于自己的层中(作为“模型”层的一部分),没有什么地方是完美的。虽然有时可以使用不同的实现方式,但在每种情况下都存在权衡。

创建用于业务逻辑的另一层代价在于你必须要真正封装你的代码。如果你过于激进,也可能会在实体和域模型之间产生重复(如果您的数据库关系语义已经处理了您的业务逻辑)。

视图

视图是应用程序最容易发生变化的部分,因此也是最脆弱的部分。

由于需要支持所有各种视图状态转换,因此在视图中正确处理业务逻辑非常困难。

现在人们都知道这样做是极不可取的 :)

存储库

这里的问题在于维护和抽象的纯洁性。违反这一点可能会使人们感到困惑,并使您的应用程序难以维护。

来自Repository 模式的 P of EAA 文章

存储库充当域和数据映射层之间的中介,就像一个内存中的域对象集合。

存储库是一种将您的数据存储呈现为持有域对象的集合的抽象。

其中不应该包含任何领域逻辑。相反,它应该存在于您的领域对象中(按定义,因为您的业务逻辑就是您的领域)。

否则(使您的存储库具有双重功能并验证域逻辑)将违反SRP(单一责任原则),并且可能会产生代码异味。

您可以拥有更高级别的领域对象来处理领域对象集合(例如对象集合内的依赖关系、大小限制等)以验证领域逻辑。它们仍将在底层使用您的存储库来执行域对象的最终存储/检索,因此它们不会承担双重职责(因此也不违反 SRP)。

控制器

控制器也不是放置业务逻辑的好地方。控制器的工作是在控制器和模型之间进行协调。

模型是领域,领域便是你的业务逻辑。

实体

你可以考虑将领域数据放在实体中。

但是,如果实体已经连接,则访问导航属性时必须小心,因为这可能会触发意外的数据库查询或异常(取决于上下文是否被释放)。解除它们的连接也是一个问题,因为除非你在从上下文分离它们后显式重新连接对象到彼此,否则会破坏你的对象图。

如果你创建单独的领域模型类,你可以将实体视为仅限于DTOs

编辑:IValidatableObject

我刚刚了解到 Entity Framework 4.1 中的一个功能,你可能想要检查一下:接口IValidatableObject

你可以将你的实体类设置为 partial 类,在 partial 类中实现该接口。这样,当你保存时,Entity Framework 将调用Validate方法,你也可以在适当的时候调用Validate方法。

这可能有助于你在其他情况下避免将持久化模型与领域模型分开。

请参阅此文章:http://msdn.microsoft.com/en-us/data/gg193959

附注:视图/视图模型

如果你考虑这个问题,我建议你避免将实体传回视图。它会在许多情况下出现错误(例如Javascript序列化以存储视图状态),并且在其他情况下会导致意外的数据库查询。相反,应该传回简单类型(如字符串、整数、列表、哈希集合、字典等),或者构造视图模型类以传递给视图。


感谢您提供的出色答案!有一个问题:如果我们将业务逻辑放在模型类中,我们应该把模型视为ViewModel(类似于WPF)吗? - Alexander
@Alexander:确实有一些类似之处。但我不确定您在看到视图模型这个术语时会想到哪些内容。视图与域模型对象之间的一对一关系远不如视图与视图模型对象之间的关系常见。而且,根据需要设计您的域模型以适应多个应用程序的需求更加常见(例如在Web GUI和Web服务中都使用),而设计视图模型则要少得多(通常仅限于单个WPF应用程序,尽管可能涉及该应用程序的多个部分)。 - Merlyn Morgan-Graham
@Alexander:看看我刚刚进行的编辑(在底部),涉及到IValidatableObject接口。这并不能完全解决所有问题,但在某些情况下可以帮助你避免将领域模型与持久化模型分离。 - Merlyn Morgan-Graham

6
在编程中,添加服务层以将模型传递到存储库,可以添加与控制器对应的服务类。例如,如果您使用UserController和User Model,则可以将User Model传递给UserService类。
在这里,服务层可以作为存储库和控制器之间的桥梁,以确保控制器和存储库的分离得到很好地建立。

5

+1;在我回答之后阅读此内容。更加简洁,但表达的是同一观点 :) - Merlyn Morgan-Graham

1

我同意上述观点,控制器不应该负责业务逻辑,只需返回适当的视图。我使用服务层提供业务逻辑和视图模型创建,以便控制器仅将从服务返回的模型传递给视图。

我还确保我的视图模型是简单的DTO,并且服务只需知道如何适当地填充属性即可。


0
在我看来,这取决于业务逻辑。如果逻辑基于输入验证和输入规则,那么最好放在模型中。然而,如果基于工作流的业务规则可能需要在控制器中,例如,用户选择选项A,然后被重定向到不同的页面/表单,而如果选择了选项B,则会有所不同。如果业务规则涉及数据持久性,则可能需要放在存储库中(对我来说似乎很奇怪)。关于这个问题有很多讨论,但最终取决于您或您的团队对实现方式如何影响最终产品的可维护性和灵活性的看法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接