I am designing an ASP.NET MVC3 application, and I would like to have a clear separation of concerns in a 3 layer architecture. I am using Fluent NHibernate as the ORM, the Repository pattern to work with the entities mapped by NHibernate. I would like to add a proper business layer with a Unit Of Work pattern, keeping the MVC portion only for presentation (by using ViewModels that map to the nHibernate entities through the business layer). This article describes the combined 3-tier and MVC architectures nicely.
我正在设计一个ASP.NET MVC3应用程序,我想在3层架构中清楚地分离关注点。我使用Fluent NHibernate作为ORM,Repository模式与NHibernate映射的实体一起使用。我想添加一个具有Unit Of Work模式的适当业务层,保留MVC部分仅用于表示(通过使用通过业务层映射到nHibernate实体的ViewModels)。本文很好地描述了组合的3层和MVC架构。
According to this MVC + unit of work + repository article I don't see a clear distinction of a business layer. The unit of work class presents strongly typed getters for each repository type, which looks appropriate for a business layer. However, it exposes a Save method, which I think would translate to BeginTransaction and CommitTransaction methods with nHibernate. This begs some questions:
根据这个MVC +工作单元+存储库文章,我没有看到业务层的明显区别。工作单元类为每个存储库类型提供强类型的getter,它看起来适合业务层。但是,它暴露了一个Save方法,我认为它会转换为使用nHibernate的BeginTransaction和CommitTransaction方法。这引出了一些问题:
1) Is exposing transaction control to MVC a good idea? At which stage should transaction control happen? Seems to me that MVC should not be responsible for transactions, but how to avoid that?
1)将事务控制暴露给MVC是一个好主意吗?交易控制应该在哪个阶段发生?在我看来,MVC不应该对交易负责,但如何避免这种情况?
2) Should there be some automatic way to handle transactions? This ActionFilter implementation is semi-automatic but the transaction control is clearly in the MVC section, which is not the business layer.
2)是否应该有一些自动处理交易的方法?此ActionFilter实现是半自动的,但事务控制显然位于MVC部分,而不是业务层。
3) Is the UnitOfWork class the same as a business layer class?
- if so, does that mean that we can add custom business logic methods into it?
- if not, do we wrap the unit of work with some other class(es) that contains business logic methods?
3)UnitOfWork类与业务层类相同吗? - 如果是这样,这是否意味着我们可以在其中添加自定义业务逻辑方法? - 如果没有,我们是否将工作单元包含在包含业务逻辑方法的其他类中?
I appreciate any ideas or examples. Thank you.
我感谢任何想法或例子。谢谢。
3 个解决方案
#1
12
First of all I want to clarify a little mis-conception about the business layer, as you want to use the Repository pattern and your setup is a candidate to Domain Driven Design, then the business layer is actually [the Domain Model (Entities and Value Objects where you design your business logic in an object oriented fashion in entities and objects) , and Application Layer to co-ordinate transactions and operations and commands to the domain layer], so the suggested architecture would be something like this:
首先,我想澄清一下关于业务层的一些误解,因为你想使用Repository模式,你的设置是域驱动设计的候选者,那么业务层实际上是[域模型(实体和值)您在实体和对象中以面向对象的方式设计业务逻辑的对象,以及将事务和操作以及命令协调到域层的应用层],因此建议的体系结构将是这样的:
- Presentation (MVC) [OrderView, OrderPresentationModel, OrderController]
- Application [OrderService]
- Use UnitOfWork (Transactions) and Repositories to execute domain logic
- DTOs [OrderDTO, CustomerDTO]
使用UnitOfWork(Transactions)和Repositories来执行域逻辑
DTO [OrderDTO,CustomerDTO]
- Domain
- Entities and Value Objects [Order, Customer, LineItem, Address]
- Repository Interfaces [IOrderRepository, ICustomerRepository]
- (optional) Unit of Work Interface [IUnitOfWork]
实体和价值对象[订单,客户,LineItem,地址]
存储库接口[IOrderRepository,ICustomerRepository]
(可选)工作单元接口[IUnitOfWork]
- Infrastructure.DataAccess (Using ORM or Data Access Technology)
- Repositories [OrderRepository, CustomerRepository]
- (optional) Unit of Work [UnitOfWork]
存储库[OrderRepository,CustomerRepository]
(可选)工作单元[UnitOfWork]
- Infrastructure.Common
- Logging
- Utilities
演示文稿(MVC)[OrderView,OrderPresentationModel,OrderController]
应用程序[OrderService]使用UnitOfWork(Transactions)和存储库来执行域逻辑DTO [OrderDTO,CustomerDTO]
域实体和值对象[Order,Customer,LineItem,Address]存储库接口[IOrderRepository,ICustomerRepository](可选)工作单元接口[IUnitOfWork]
Infrastructure.DataAccess(使用ORM或数据访问技术)存储库[OrderRepository,CustomerRepository](可选)工作单元[UnitOfWork]
Infrastructure.Common Logging Utilities
Example scenario:
[Presentation] OrderController:
_orderService.CreateOrder(OrderDTO);
[Application] OrderService:
_unitOfWork.BeginTransaction();
var customer = _customerRepository.GetById(orderDTO.CustomerId);
var order = new Order() { Customer=customer, Price=orderDTO.Price, ... }
_orderRepository.Add(order);
_unitOfWork.Commit();
About your questions:
关于你的问题:
1) Is exposing transaction control to MVC a good idea? At which stage should transaction control happen? Seems to me that MVC should not be responsible for transactions, but how to avoid that?
1)将事务控制暴露给MVC是一个好主意吗?交易控制应该在哪个阶段发生?在我看来,MVC不应该对交易负责,但如何避免这种情况?
No, i would prefer to separate it in application layer in order to make design flexible to support different presentations.
不,我更愿意在应用层中将其分开,以使设计灵活,以支持不同的演示。
2) Should there be some automatic way to handle transactions? This ActionFilter implementation is semi-automatic but the transaction control is clearly in the MVC section, which is not the business layer.
2)是否应该有一些自动处理交易的方法?此ActionFilter实现是半自动的,但事务控制显然位于MVC部分,而不是业务层。
Use transactions in application layer.
在应用程序层中使用事务。
3) Is the UnitOfWork class the same as a business layer class? - if so, does that mean that we can add custom business logic methods into it? - if not, do we wrap the unit of work with some other class(es) that contains business logic methods?
3)UnitOfWork类与业务层类相同吗? - 如果是这样,这是否意味着我们可以在其中添加自定义业务逻辑方法? - 如果没有,我们是否将工作单元包含在包含业务逻辑方法的其他类中?
No, it is just a way to group tasks into transactions. The business logic actually is encapsulated in entities and if the logic is not related to one entity it should be implemented in domain services [TransferService.Transfer(account1, account2, amount)], for co-ordinations, accessing repositories, and transactions the application layer is the place.
不,这只是将任务分组到事务中的一种方法。业务逻辑实际上封装在实体中,如果逻辑与一个实体无关,它应该在域服务[TransferService.Transfer(account1,account2,amount)]中实现,用于协调,访问存储库和事务应用程序层是地方。
#2
1
Have you looked into the S#arp Architecture? It has built-in MVC Transaction handling, using Action Filters.
你有没有看过S#arp架构?它使用动作过滤器内置MVC事务处理。
I'm usually a layering purist, so I wasn't psyched about letting MVC open the view, but I've come to like it.
我通常是一个分层纯粹主义者,所以我对让MVC打开视图并不感到兴奋,但我喜欢它。
There are pro's and con's, but here are some advantages of the Open Session In View pattern.:
有pro和con,但这里有Open Session In View模式的一些优点:
- Lazy Loading -- It will simplify your data access if you can rely on lazy loading in your MVC Views. No need to explicitly join to all tables required by the view. (Be sure to avoid the N+1 problem by joining explicitly when lazy loading would generate a ridiculous number of queries. Data grids are a common culprit here.)
- Simpler BSO layer -- your BSO doesn't need to worry about sessions. It's assumed that you're already working in the context of a session.
延迟加载 - 如果您可以依赖MVC视图中的延迟加载,它将简化您的数据访问。无需显式连接到视图所需的所有表。 (当延迟加载会产生大量的查询时,请务必通过显式连接来避免N + 1问题。数据网格是这里常见的罪魁祸首。)
更简单的BSO层 - 您的BSO不需要担心会话。假设您已经在会话的上下文中工作。
If you don't want to go with S#arp, you can still implement Open-Session-In-View yourself with only a few lines of code in an ActionFilter. On the Action Executing method, open the session. In the action executed method, commit, close, and dispose. This is what we're doing on my project and it has worked well for us.
如果您不想使用S#arp,您仍然可以在ActionFilter中使用几行代码自行实现Open-Session-In-View。在Action Executing方法上,打开会话。在动作执行的方法中,提交,关闭和处置。这就是我们在项目中所做的事情,它对我们来说效果很好。
#3
0
The problem you have with any web based app is that there has to be some coupling of the UI to the buisness layer due to the need to manage object lifetimes by the HTTP Session. In a typical desktop application you don't have to worry about sessions, so this makes it easy to move all transaction handling further down the chain.
任何基于Web的应用程序的问题在于,由于需要通过HTTP会话管理对象生存期,因此必须将UI与业务层进行一些耦合。在典型的桌面应用程序中,您不必担心会话,因此可以轻松地将所有事务处理转移到链中。
Consider where you want to reuse the same logic in three apps, a Web Site, a Web Service, and a Desktop application. Without exposing the transaction handling to the presentation tier, there's no good way to deal with transaction commits, beacuse the business layer is ignorant of how long the objects will exist.
考虑在三个应用程序,网站,Web服务和桌面应用程序中重用相同逻辑的位置。在不将事务处理暴露给表示层的情况下,处理事务提交没有好办法,因为业务层不知道对象存在多长时间。
So your choice is, either make sure you commit everything in every method of your buisness objects, or expose the transaction to the UI.
因此,您可以选择确保在商务对象的每个方法中提交所有内容,或者将事务公开给UI。
A third alternative would be to build a fairly complex session management controller, which I don't even want to think about... The session management controller could be coupled to the ui and the business logic, seperating them to some extent.. But that would require a lot more analysis.
第三种选择是构建一个相当复杂的会话管理控制器,我甚至不想考虑......会话管理控制器可以耦合到ui和业务逻辑,在某种程度上分离它们。但是这将需要更多的分析。
#1
12
First of all I want to clarify a little mis-conception about the business layer, as you want to use the Repository pattern and your setup is a candidate to Domain Driven Design, then the business layer is actually [the Domain Model (Entities and Value Objects where you design your business logic in an object oriented fashion in entities and objects) , and Application Layer to co-ordinate transactions and operations and commands to the domain layer], so the suggested architecture would be something like this:
首先,我想澄清一下关于业务层的一些误解,因为你想使用Repository模式,你的设置是域驱动设计的候选者,那么业务层实际上是[域模型(实体和值)您在实体和对象中以面向对象的方式设计业务逻辑的对象,以及将事务和操作以及命令协调到域层的应用层],因此建议的体系结构将是这样的:
- Presentation (MVC) [OrderView, OrderPresentationModel, OrderController]
- Application [OrderService]
- Use UnitOfWork (Transactions) and Repositories to execute domain logic
- DTOs [OrderDTO, CustomerDTO]
使用UnitOfWork(Transactions)和Repositories来执行域逻辑
DTO [OrderDTO,CustomerDTO]
- Domain
- Entities and Value Objects [Order, Customer, LineItem, Address]
- Repository Interfaces [IOrderRepository, ICustomerRepository]
- (optional) Unit of Work Interface [IUnitOfWork]
实体和价值对象[订单,客户,LineItem,地址]
存储库接口[IOrderRepository,ICustomerRepository]
(可选)工作单元接口[IUnitOfWork]
- Infrastructure.DataAccess (Using ORM or Data Access Technology)
- Repositories [OrderRepository, CustomerRepository]
- (optional) Unit of Work [UnitOfWork]
存储库[OrderRepository,CustomerRepository]
(可选)工作单元[UnitOfWork]
- Infrastructure.Common
- Logging
- Utilities
演示文稿(MVC)[OrderView,OrderPresentationModel,OrderController]
应用程序[OrderService]使用UnitOfWork(Transactions)和存储库来执行域逻辑DTO [OrderDTO,CustomerDTO]
域实体和值对象[Order,Customer,LineItem,Address]存储库接口[IOrderRepository,ICustomerRepository](可选)工作单元接口[IUnitOfWork]
Infrastructure.DataAccess(使用ORM或数据访问技术)存储库[OrderRepository,CustomerRepository](可选)工作单元[UnitOfWork]
Infrastructure.Common Logging Utilities
Example scenario:
[Presentation] OrderController:
_orderService.CreateOrder(OrderDTO);
[Application] OrderService:
_unitOfWork.BeginTransaction();
var customer = _customerRepository.GetById(orderDTO.CustomerId);
var order = new Order() { Customer=customer, Price=orderDTO.Price, ... }
_orderRepository.Add(order);
_unitOfWork.Commit();
About your questions:
关于你的问题:
1) Is exposing transaction control to MVC a good idea? At which stage should transaction control happen? Seems to me that MVC should not be responsible for transactions, but how to avoid that?
1)将事务控制暴露给MVC是一个好主意吗?交易控制应该在哪个阶段发生?在我看来,MVC不应该对交易负责,但如何避免这种情况?
No, i would prefer to separate it in application layer in order to make design flexible to support different presentations.
不,我更愿意在应用层中将其分开,以使设计灵活,以支持不同的演示。
2) Should there be some automatic way to handle transactions? This ActionFilter implementation is semi-automatic but the transaction control is clearly in the MVC section, which is not the business layer.
2)是否应该有一些自动处理交易的方法?此ActionFilter实现是半自动的,但事务控制显然位于MVC部分,而不是业务层。
Use transactions in application layer.
在应用程序层中使用事务。
3) Is the UnitOfWork class the same as a business layer class? - if so, does that mean that we can add custom business logic methods into it? - if not, do we wrap the unit of work with some other class(es) that contains business logic methods?
3)UnitOfWork类与业务层类相同吗? - 如果是这样,这是否意味着我们可以在其中添加自定义业务逻辑方法? - 如果没有,我们是否将工作单元包含在包含业务逻辑方法的其他类中?
No, it is just a way to group tasks into transactions. The business logic actually is encapsulated in entities and if the logic is not related to one entity it should be implemented in domain services [TransferService.Transfer(account1, account2, amount)], for co-ordinations, accessing repositories, and transactions the application layer is the place.
不,这只是将任务分组到事务中的一种方法。业务逻辑实际上封装在实体中,如果逻辑与一个实体无关,它应该在域服务[TransferService.Transfer(account1,account2,amount)]中实现,用于协调,访问存储库和事务应用程序层是地方。
#2
1
Have you looked into the S#arp Architecture? It has built-in MVC Transaction handling, using Action Filters.
你有没有看过S#arp架构?它使用动作过滤器内置MVC事务处理。
I'm usually a layering purist, so I wasn't psyched about letting MVC open the view, but I've come to like it.
我通常是一个分层纯粹主义者,所以我对让MVC打开视图并不感到兴奋,但我喜欢它。
There are pro's and con's, but here are some advantages of the Open Session In View pattern.:
有pro和con,但这里有Open Session In View模式的一些优点:
- Lazy Loading -- It will simplify your data access if you can rely on lazy loading in your MVC Views. No need to explicitly join to all tables required by the view. (Be sure to avoid the N+1 problem by joining explicitly when lazy loading would generate a ridiculous number of queries. Data grids are a common culprit here.)
- Simpler BSO layer -- your BSO doesn't need to worry about sessions. It's assumed that you're already working in the context of a session.
延迟加载 - 如果您可以依赖MVC视图中的延迟加载,它将简化您的数据访问。无需显式连接到视图所需的所有表。 (当延迟加载会产生大量的查询时,请务必通过显式连接来避免N + 1问题。数据网格是这里常见的罪魁祸首。)
更简单的BSO层 - 您的BSO不需要担心会话。假设您已经在会话的上下文中工作。
If you don't want to go with S#arp, you can still implement Open-Session-In-View yourself with only a few lines of code in an ActionFilter. On the Action Executing method, open the session. In the action executed method, commit, close, and dispose. This is what we're doing on my project and it has worked well for us.
如果您不想使用S#arp,您仍然可以在ActionFilter中使用几行代码自行实现Open-Session-In-View。在Action Executing方法上,打开会话。在动作执行的方法中,提交,关闭和处置。这就是我们在项目中所做的事情,它对我们来说效果很好。
#3
0
The problem you have with any web based app is that there has to be some coupling of the UI to the buisness layer due to the need to manage object lifetimes by the HTTP Session. In a typical desktop application you don't have to worry about sessions, so this makes it easy to move all transaction handling further down the chain.
任何基于Web的应用程序的问题在于,由于需要通过HTTP会话管理对象生存期,因此必须将UI与业务层进行一些耦合。在典型的桌面应用程序中,您不必担心会话,因此可以轻松地将所有事务处理转移到链中。
Consider where you want to reuse the same logic in three apps, a Web Site, a Web Service, and a Desktop application. Without exposing the transaction handling to the presentation tier, there's no good way to deal with transaction commits, beacuse the business layer is ignorant of how long the objects will exist.
考虑在三个应用程序,网站,Web服务和桌面应用程序中重用相同逻辑的位置。在不将事务处理暴露给表示层的情况下,处理事务提交没有好办法,因为业务层不知道对象存在多长时间。
So your choice is, either make sure you commit everything in every method of your buisness objects, or expose the transaction to the UI.
因此,您可以选择确保在商务对象的每个方法中提交所有内容,或者将事务公开给UI。
A third alternative would be to build a fairly complex session management controller, which I don't even want to think about... The session management controller could be coupled to the ui and the business logic, seperating them to some extent.. But that would require a lot more analysis.
第三种选择是构建一个相当复杂的会话管理控制器,我甚至不想考虑......会话管理控制器可以耦合到ui和业务逻辑,在某种程度上分离它们。但是这将需要更多的分析。