NHibernate.3.0.Cookbook第三章第6节的翻译

Using the Conversation per Business Transaction pattern

使用Conversation per Business Transaction模式

  在桌面应用程序中领一个常用的会话管理模式是:Conversation  per Business Transaction, 缩写为CpBT. 本节介绍如何使用CpBT的一个实现,该实现来自非官方的开源的NHibernate组件项目.uNhAddIns项目(unofficial NHibernate AddIns project,)最初由NHibernate领导者Fabio Maulo启动,并且由几个知名的NHibernate参与者来维护.

准备

  你需要从站点http://code.google.com/p/unhaddins/ 下载最新的uNhAddIns二进制包,并将她解压到Lib文件夹.

步骤

1.   创建一个名为CpBT的控制台程序.
2.   添加引用:Castle.Core,  Castle.Windsor,  log4net,  NHibernate, NHibernate.ByteCode.Castle,  uNhAddIns,  uNhAddIns.Adapters ,
uNhAddIns.CastleAdapters,和Eg.Core项目.
3.   添加应用程序配置文件,并添加标准的log4net和hibernate-configuration节点,可以参考第二章中的示例.
4.   在hibernate-configuration节点的session-factory元素中,

将urrent_session_context_class设置为uNhAddIns.SessionEasier.Conversations.ThreadLocalConversationalSessionContext, uNhAddIns
5.   添加一个名为DataAccess的文件夹.
6.   在该文件夹下,添加一个有两个方法的接口:IDao<TEntity>:

View Code
TEntity Get(Guid Id);
void Save(TEntity entity);

7.   添加IDao<TEntity>接口的实现:Dao<TEntity>,代码如下:

View Code
private readonly ISessionFactory _sessionFactory;
public Dao(ISessionFactory sessionFactory)
{
  _sessionFactory = sessionFactory;
}
protected ISession Session
{
  get { return _sessionFactory.GetCurrentSession(); }
}
public TEntity Get(Guid Id)
{
  return Session.Get<TEntity>(Id);
}
public void Save(TEntity entity)
{
  Session.SaveOrUpdate(entity);
}

8.   为CpBT项目添加名为ApplicationServices的文件夹:
9.   在该文件夹下,添加含有下列方法的IEditMovieModel接口:

View Code
Movie GetMovie(Guid movieId);
void SaveMovie(Movie movie);
void SaveAll();
void CancelAll();

10.  添加IEditMovieModel接口的实现:EditMovieModel,代码如下:

View Code
private readonly IDao<Movie> _movieDao;
public EditMovieModel(IDao<Movie> movieDao)
{
  _movieDao = movieDao;
}
public virtual Movie GetMovie(Guid movieId)
{
  return _movieDao.Get(movieId);
}
public virtual void SaveMovie(Movie movie)

{
  _movieDao.Save(movie);
}
public virtual void SaveAll()
{
}
public virtual void CancelAll()
{
}

11.  添加using语句:

using uNhAddIns.Adapters;

12.  为EditMovieModel布置属性,如下:

[PersistenceConversational

13.  为SaveAll方法布置属性,如下:

[PersistenceConversation(ConversationEndMode=EndMode.End)]

14.  为CancelAll方法布置属性,如下:

[PersistenceConversation(ConversationEndMode=EndMode.Abort)]

15.  添加一个名为ContainerProvider的公共静态类,为其添加下述using语句:

View Code
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using CpBT.ApplicationServices;
using CpBT.DataAccess;
using NHibernate;
using NHibernate.Engine;
using uNhAddIns.CastleAdapters;
using uNhAddIns.CastleAdapters.AutomaticConversationManagement;
using uNhAddIns.SessionEasier;
using uNhAddIns.SessionEasier.Conversations;

16.  在ContainerProvider添加下面的代码以为NHibernate和CpBT配置Castle Windsor

View Code
private static readonly IWindsorContainer _container;
public static IWindsorContainer Container
{
  get
  {
    return _container;
  }

}
static ContainerProvider()
{
  _container = new WindsorContainer();
  _container
    .AddFacility<PersistenceConversationFacility>();
  _container
    .AddFacility<FactorySupportFacility>();
  _container.Register(
    Component.For<ISessionFactoryProvider>()
    .ImplementedBy<SessionFactoryProvider>());
  _container.Register(
    Component.For<ISessionFactory>()
      .UsingFactoryMethod(
        () => _container
                .Resolve<ISessionFactoryProvider>()
                .GetFactory(null))
    );
  _container.Register(
    Component.For<ISessionWrapper>()
    .ImplementedBy<SessionWrapper>());
  _container.Register(
    Component.For<IConversationFactory>()
    .ImplementedBy<DefaultConversationFactory>());
  _container.Register(
    Component.For<IConversationsContainerAccessor>()
    .ImplementedBy<NhConversationsContainerAccessor>());
  _container.Register(
    Component.For(typeof(IDao<>))
      .ImplementedBy(typeof(Dao<>)));
  _container.Register(
    Component.For<IEditMovieModel>()
      .ImplementedBy<EditMovieModel>()
      .LifeStyle.Transient);
}

17.  在Program类中添加CreateMovie方法,代码如下:

View Code
static Movie CreateNewMovie()
{
  return new Movie()
  {
  Name = "Hackers",
  Description = "Bad",
  UnitPrice = 12.59M,
  Director = "Iain Softley",
  Actors = new List<ActorRole>()
  {
    new ActorRole()
    {
    Actor = "Jonny Lee Miller",
    Role="Zero Cool"
    },
    new ActorRole()
    {
    Actor = "Angelina Jolie",
    Role="Acid Burn"
    }
  }
  };
}

18.  最后,在Main方法中添加下面的代码:

View Code
log4net.Config.XmlConfigurator.Configure();
var container = ContainerProvider.Container;
Movie movie = CreateNewMovie();
Guid movieId;
var model = container.GetService<IEditMovieModel>();
model.SaveMovie(movie);
movieId = movie.Id;
model.SaveAll();
movie = null;
movie = model.GetMovie(movieId);
movie.Description = "Greatest Movie Ever";
model.CancelAll();
movie = null;

原理

  Conversation per Business Transaction (CpBT)介绍了长期运行的多事务的工作单元 . 一个单独的会话被保持打开状态,以允许用户和应用程序的多次交互.该会话中,在最后的提交中,等待保存所有改变时,我们会打开和提交几个事务处理. 一个典型的NHibernate应用程序使用FlushMode.Commit,这意味着在事务被提交的时候unit of work会被持久化. CpBT使用FlushMode.Never, 这种情况下,在事务被提交的时候unit of work不会被自动持久化Instead,在事务处理完成后, CpBT显式调用session.Flush()来持久化unit of work.
  在CpBT的典型使用中,会用一个类来表示业business transaction, unit of work和封装的相关业务逻辑. 每个示例都会作为数据库会话的一个上下文,该会话可以被启动,暂停,结束或异常终止,如下图所示:

  在我们的持久化会话中,以下五个会话行为分别处理不同的任务:

  • Start:终止上下文中的先前的活动会话,然后开始新的会话和事务.
  • Resume: 如果上下文中不存在会话,她会先启动一个会话,然后启动一个新的事务.
  • Pause:  提交事务.但是因为CpBT使用FlushMode.Never,所以unit of work会继续并且更改不会被持久化.
  • End:  将变更持久化到数据库,提交最终的事务并关闭会话.
  • Abort: 回滚事务并注销会话.

  在CpBT的实现中,resume隐含在每个方法的开始,pause隐含在每个方法(没有end或abort标记)的结束,这种CpBT的自动处理,通过ContainerProvider中的PersistentConversationFacility来完成.如果Castle正常返回了一个布置有PersistenceConversational属性的类,她返回的将是一个代理对象.该对象会处理所有CpBT的action.得益于面向方面的编程,我们可以简单的调用我们的业务逻辑方法而不用顾虑会话和事务的更多细节.面向方面编程将横切关注点分离,比如,将会话和事务管理从业务逻辑中分离.有关面向方面编程的更多资料请参考Wikipedia,网址为:http://en.wikipedia.org/wiki/Aspect-oriented_programming.
  在我们的Main方法中,有两个会话.在通过调用SaveMovie方法来保存新建的movie对象Hackers的时候,第一个会话开始.SaveMovie方法被封装到了一个事务中.
当该会话隐式暂停时,该事务会在方法结束时自动提交.然而,因为CpBT使用FlushMode.Never,所以该movie对象只是和会话相关联,却不会被写入数据库. 该事务只是被用来满足NHibernate关于事务使用的的要求. 她不会持久化unit of work. 当我们调用SaveAll方法时,该会话会重启以开始一个新的事务处理.因为该方法被标记为EndMode.End,所以当方法结束时, CpBT会显式调用 session.Flush().于是,包含插入新建movie对象Hackers的unit of work被持久化到数据库,最终事务被提交
  因为我们当前的会话结束了,下个会话会在调用GetMovie时开始.一个新的会话和事务开始了,通过movie的ID,movie对象Hackers从数据库中被获取.当GetMovie方法结束时,会话被提交,而unit of work(当前为空)不会被持久化.然后我们将movie的description改为"Greatest Movie Ever".然而我们很快便改了主意,并调用了CancelAll.当调用CancelAll时,我们终止了会话,并放弃了对movie的description的修改

扩展

  当我们在CpBT中依赖FlushMode.Never和会话的显式更新时,可以选用一个标识生成器(identity generator),她不需要将数据插入到数据库,只是为了创建POID(persistent object identifier).POID可以在所有RDBMS上创建标识,在Microsoft SQL Server上运行也同本地一样,为了创建ID值会引起会话中数据较早的被flush,破坏了unit of work. 如果你想终止会话,这些数据库更改将无法挽回.
  uNhAddIns也包含了对Spring framework的实现和PostSharp工具.对面向方面有扎实的理解的话,你也可以写一个你自己的.

转载于:https://www.cnblogs.com/carfieldSE/archive/2012/07/15/2591878.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值