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

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

最终,除了自己的层(作为“模型”层的一部分)之外,您的业务逻辑还没有一个完美的位置。 通常你可以通过不同的实现来逃避,但在每种情况下都有权衡。

为业务逻辑创建另一层的权衡是您必须实际封装代码。 如果你过于咄咄逼人,你的实体和你的域模型之间也可能会出现一些重复(如果你的数据库的关系语义已经处理了你的buiness逻辑)。

视图

视图是应用程序中最脆弱的部分,因为它最有可能发生变化。

由于必须支持所有各种视图状态转换,因此在视图中使业务逻辑正确也非常困难。

现在众所周知,你只是不这样做:)

知识库

这里的问题是维护和抽象的纯粹之一。 违反此规定可能会让人感到困惑并使您的应用难以维护。

来自关于存储库模式的EAA文章 :

存储库在域和数据映射层之间进行调解,其作用类似于内存中的域对象集合

存储库是一种抽象,它将您的数据存储呈现为包含域对象的集合。

没有域逻辑应该驻留在其中。 相反,它应该存在于您的域对象中(根据定义,因为您的业务逻辑您的域)。

否则(使您的存储库执行双重任务并validation域逻辑)将违反SRP( 单一责任原则 ),并且会产生代码异味。

您可以使用更高级别的域对象来处理域对象集合,以validation域逻辑(例如对象集合中的依赖关系,大小限制等)。 他们仍将使用您的存储库来进行域对象的最终存储/检索,因此他们不会执行双重任务(因此不会违反SRP)。

调节器

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

模型是域,域是您的业务逻辑。

实体

您可以考虑将域数据放入实体中。

但是,如果附加了实体,则在访问导航属性时必须小心,因为您可以触发无意的数据库查询或exception(取决于您的上下文是否被处置)。 分离它们也是一个问题,因为它会破坏您的对象图,除非您在将对象从上下文中分离后明确地重新附加对象。

如果您创建单独的域模型类,则可以考虑仅将实体视为DTO 。

编辑:IValidatableObject

我刚刚发现了您可能要查看的Entity Framework 4.1中的一个function: IValidatableObject接口。

您可以使实体成为部分类,并在部分类中实现此接口。 执行此操作时,entity framework将在保存时调用Validate ,并且只要有意义,您就可以调用Validate

在其他情况下,这可以帮助您避免将持久性模型与域模型分开。

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

附注:视图/视图模型

如果您正在考虑它,我建议您避免将实体传递回视图的诱惑。 它会在很多情况下中断(例如,Javascript序列化以存储视图状态),并在其他情况下导致无意的数据库查询。 传递简单类型(字符串,整数,列表,哈希集,字典等),或构造视图模型类以传递给视图。

添加服务层以将模型传递到Repository,其中可以添加与控制器对应的Service类。 例如,如果使用UserController和User Model,则可以将User Model传递给UserService类。

这里,服务层可以充当存储库和控制器之间的桥梁,以便很好地建立Controller和存储库的分离。

业务逻辑应该存在于您的域模型中。

请看看这个答案。

ASP.NET MVC – 控制器中是否应存在业务逻辑?

我同意上述内容,控制器不应仅仅为返回适当的视图而负责业务逻辑。 我使用服务层来提供业务逻辑和视图模型创建,以便控制器简单地将从服务返回的模型传递给视图。

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

在我看来,这取决于业务逻辑。 逻辑是基于输入和输入规则的validation,如果是这样,最好是在模型上。 但是,如果是基于工作流的业务规则,则可能需要在控制器中,例如,用户选择选项A,然后重定向到与选择选项B时不同的页面/forms。 如果业务规则必须处理数据持久性,那么它可能需要进入存储库(将它放在那里似乎很奇怪)。 关于这一点有很多讨论,但它取决于您或您的团队关于最终产品如何基于实施的可维护性和灵活性的观点。