在业务层中使用工作单元/存储库的正确方法是什么?
使用工作单元/存储库模式构建了一个小型应用程序后,我正在努力了解如何在我的业务层中正确使用它。我的应用程序有一个数据访问层,可以是 NHibernate 或实体框架。我可以轻松地在这些之间切换。
我有许多存储库,例如客户、订单等。我的工作单元将是 ISession 或对象上下文,具体取决于我想使用哪个 DAL 进行测试。
我的业务层包含一个业务方法 - CreateOrder()。我很难理解的是,我应该在业务层的哪个位置初始化我的工作单元和存储库。
专注于 Nhibernate,我的 DAL 看起来像:
public class NHibernateDAL : IUnitOfWork
{
log4net.ILog log = log4net.LogManager.GetLogger(typeof(NHibernateDAL));
ISession context;
public NHibernateDAL()
{
context = SessionProvider.OpenSession();
this.Context.BeginTransaction();
CurrentSessionContext.Bind(context);
}
public ISession Context
{
get { return context; }
}
public void Commit()
{
this.Context.Transaction.Commit();
context.Close();
}
public void Dispose()
{
ISession session = CurrentSessionContext.Unbind(SessionProvider.SessionFactory);
session.Close();
}
}
在我的业务层中,我想知道我应该在哪里声明我的工作单元和存储库。它们是在类级别还是在 CreateOrder 方法中声明的?
例如:
public class BusinessLogic
{
UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL);
NhRepository<Order> _orderRepository = new NhRepository<Order>(_unitOfWork);
NhRepository<Customer> _customerRepository = new NhRepository<Customer>(_unitOfWork);
....
public void CreateOrder(.....)
{
Order order = new Order();
_orderRepository.Add(order);
_unitOfWork.Commit();
}
}
上面的代码仅在第一次调用 CreateOrder() 方法时有效,但对于后续调用则无效,因为会话已关闭。我尝试在提交事务后删除“context.Close()”调用,但这也失败了。尽管上述方法不起作用,但对我来说,在此范围内声明我的存储库和工作单元似乎更正确。
但是,如果我按如下方式实现它,它可以正常工作,但在方法本身的范围内声明存储库和工作单元似乎不自然。如果我有大量的业务方法,那么我将在各处声明存储库和工作单元:
public class BusinessLogic
{
public void CreateOrder(.....)
{
UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL);
var _orderRepository = new NhRepository<Order>(_unitOfWork);
NhRepository<Customer> _customerRepository = null;
Order order = new Order();
_orderRepository.Add(order);
_unitOfWork.Commit();
}
}
如果我要通过类级别声明来实现这一点,那么我认为我需要一些方法来重新打开相同的工作单元在 CreateOrder 方法的开头。
在业务层中使用工作单元和存储库的正确方法是什么?
Having built a small application using the Unit of Work/Repository pattern, I am struggling to understand how to use this properly within my business layer. My application has a a data access layer which can be either NHibernate or the Entity Framework. I can switch between these easily.
I have a number of repositories, for example, Customer, Order etc. My unit of work will be either an ISession or an Object Context depending on which DAL I want to test with.
My business layer contains a single business method - CreateOrder(). What I am struggling to understand is where in the business layer I should be initialising my unit of work and my repositories.
Focusing on Nhibernate, my DAL looks like:
public class NHibernateDAL : IUnitOfWork
{
log4net.ILog log = log4net.LogManager.GetLogger(typeof(NHibernateDAL));
ISession context;
public NHibernateDAL()
{
context = SessionProvider.OpenSession();
this.Context.BeginTransaction();
CurrentSessionContext.Bind(context);
}
public ISession Context
{
get { return context; }
}
public void Commit()
{
this.Context.Transaction.Commit();
context.Close();
}
public void Dispose()
{
ISession session = CurrentSessionContext.Unbind(SessionProvider.SessionFactory);
session.Close();
}
}
Within my business layer, I want to know where I should be declaring my Unit of Work and repositories. Are they declared at class level or within the CreateOrder method?
For example:
public class BusinessLogic
{
UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL);
NhRepository<Order> _orderRepository = new NhRepository<Order>(_unitOfWork);
NhRepository<Customer> _customerRepository = new NhRepository<Customer>(_unitOfWork);
....
public void CreateOrder(.....)
{
Order order = new Order();
_orderRepository.Add(order);
_unitOfWork.Commit();
}
}
The above code works only for the first time the CreateOrder() method is called, but not for subsequent calls because the session is closed. I have tried removing the 'context.Close()' call after committing the transaction but this also fails. Although the above approach doesn't work, it seems more correct to me to declare my repositories and unit of work with this scope.
However, if I implement it as below instead it works fine, but it seems unnatural to declare the repositories and unit of work within the scope of the method itself. If I had a tonne of business methods then I would be declaring repositories and Units of Work all over the place:
public class BusinessLogic
{
public void CreateOrder(.....)
{
UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL);
var _orderRepository = new NhRepository<Order>(_unitOfWork);
NhRepository<Customer> _customerRepository = null;
Order order = new Order();
_orderRepository.Add(order);
_unitOfWork.Commit();
}
}
If I were to implement this with class level declaration then I think I would need some means of re-opening the same unit of work at the start of the CreateOrder method.
What is the correct way to use the unit of work and repositories within the business layer?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在我看来你几乎已经明白了。在我们的新服务器堆栈中,我有这样的设置:
看起来几乎像你在那里的设置。虽然我们使用Unity来定位你所谓的业务层。 (我们只是称其为函数处理器)
不过,我强烈建议您不要将 UnitOfWork 保留在类级别。毕竟每个谨慎的函数都是一个工作单元。所以我的就是这样的(为了保护无辜者,名称已被更改):
我们还对何时进行范围进行了长时间的讨论。提交,虽然查询不需要它,但它为每个函数建立了一致的模式应用层。顺便说一句,我们使用 NCommon 作为我们的存储库/工作单元模式,并且不必将 UoW 传递到存储库。
Looks to me like you've almost got it. In our new server stack I have this setup:
Looks almost like what you've got there. Though we use Unity to locate what you call the business layer. (we just call it our function processor)
What I would highly suggest, though, is that you do NOT keep the UnitOfWork at the class level. After all each descreet function is a unit of work. So mine is like this (the names have been changed to protect the innocent):
We also had a long discussion on when to do a scope.Commit and while it isn't needed for queries, it establishes a consistent pattern for every function in the application layer. BTW we are using NCommon for our repository/unitofwork patterns and do not have to pass the UoW to the repository.
您的 IUnitOfWork 实现包含所有存储库。
您的 IUnitOfWork 会像 mvc 控制器一样注入到表示层中。
您的 IUnitOfWork 已注入到 mvc 控制器中。
您的 IRepository 被注入到您的 UnitOfWork 实现中。
Your IUnitOfWork implementation contains all repositories.
Your IUnitOfWork is injected into your presentation layer like mvc controller.
Your IUnitOfWork is injected into mvc controller.
Your IRepository is injected into your UnitOfWork implementation.