需要一个使用 nhibernate 的简单示例 +工作单元 +存储库模式 +服务层+忍者
我正在使用
- nhibernate + fluent nhibernate
- asp.net mvc 3
- ninject
目前我正在使用 nhibernate、ninject 以及存储库模式和服务层。
所以我有这个
ninject
public class NhibernateSessionFactory
{
public ISessionFactory GetSessionFactory()
{
ISessionFactory fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Framework.Data.Mapping.TableAMap>().Conventions.Add(ForeignKey.EndsWith("Id")))
.ExposeConfiguration(cfg => cfg.SetProperty("adonet.batch_size", "20"))
.ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"))
//.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
return fluentConfiguration;
}
private static void BuidSchema(NHibernate.Cfg.Configuration config)
{
new NHibernate.Tool.hbm2ddl.SchemaExport(config).Create(false, true);
}
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope()
.OnActivation(StartTransaction)
.OnDeactivation(CommitTransaction);
}
public void CommitTransaction(ISession session)
{
if (session.Transaction.IsActive)
{
session.Transaction.Commit();
}
}
public void StartTransaction(ISession session)
{
if (!session.Transaction.IsActive)
{
session.BeginTransaction();
}
}
}
所以我在应用程序的生命周期内创建一次 nhibernate 会话工厂,然后在需要时使用它为我提供会话。
交易开始 我开始一项交易,最后关闭交易。
我这样做的原因是因为当我使用 nhibernate profiler 时,我会收到很多关于使用 隐式的警告这种做法给问题贴了创可贴,但从未真正解决它(它减少了数量,但任何延迟加载的东西仍然会遇到这个问题)。
一个示例存储库
public class CalendarRepo : ICalendarRepo
{
private readonly ISession session;
public CalendarRepo(ISession session)
{
this.session = session;
}
public List<CalendarAppointment> RepeatingAppointments(int repeatingId)
{
List<CalendarAppointment> calendarAppointments = session.Query<CalendarAppointment>().Where(x => x.RepeatingId == repeatingId && x.RepeatingId != 0)
.Take(QueryLimits.Appointments)
.ToList();
return calendarAppointments;
}
}
服务层
public class CalendarService : ICalendarService
{
private readonly ICalendarRepo calendarRepo;
public CalendarService(ICalendarRepo calendarRepo)
{
this.calendarRepo = calendarRepo;
}
// normally would return something and take in params
public void SampleServiceMethod()
{
// do some checks if needed
// call up the repository
// call commit
// done.
}
}
这基本上就是我所拥有的。
我想使用工作单元模式,这样我就可以提交更多的事情并正确处理事务(现在我被告知我做的不太正确)
所以我正在寻找一个简单的例子来说明如何让它们全部实现共同努力,找出目前为止我需要改变多少。
我看到的大多数教程都比我想要的更复杂。大多数人都做 TDD 并制作通用存储库,这很好,但在我到达那个阶段之前,我希望看到一个教程,它可以简单地完成任务,即使它是重复的代码。
编辑
所以我一直在研究它并想出了这个非常非常简单的例子。我不确定我做得是否正确。
Ninject
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
kernel.Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
kernel.Bind<ITable1Repo>().To<Table1Repo>();
kernel.Bind<ITable1Service>().To<Table1Service>();
kernel.Bind<IUnitofWork>().To<UnitofWork>();
}
nhibernate 工厂类如原始帖子所示。
// Controller
public class Default1Controller : Controller
{
private readonly ITable1Service table1Service;
//
// GET: /Default1/
public Default1Controller(ITable1Service table1Service)
{
this.table1Service = table1Service;
}
public ActionResult Index()
{
table1Service.Save();
return View();
}
}
// 域
public class Table1
{
public virtual int Id { get; private set; }
public virtual string C1 { get; set; }
public virtual string C2 { get; set; }
}
// Fluent Mapping
public class Table1Mapping : ClassMap<Table1>
{
public Table1Mapping()
{
Id(x => x.Id);
Map(x => x.C1);
Map(x => x.C2);
}
}
//Repo
public class Table1Repo : unitofwork.Models.Repository.ITable1Repo
{
private readonly ISession session;
public Table1Repo(ISession session)
{
this.session = session;
}
public void Create(Table1 tbl1)
{
session.Save(tbl1);
}
}
// 服务层
public class Table1Service : unitofwork.Models.Service.ITable1Service
{
private readonly ITable1Repo table1Repo;
private readonly IUnitofWork unitOfWork;
public Table1Service(ITable1Repo table1Repo, IUnitofWork unitOfWork)
{
this.table1Repo = table1Repo;
this.unitOfWork = unitOfWork;
}
public void Save()
{
Table1 a = new Table1();
a.C1 = "test";
a.C2 = "test2";
table1Repo.Create(a);
unitOfWork.Commit();
}
}
// 工作单元
public class UnitofWork : unitofwork.Models.IUnitofWork
{
private readonly ITransaction transaction;
private readonly ISession session;
public UnitofWork(ISession session)
{
this.session = session;
session.FlushMode = FlushMode.Auto;
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don't have an active transaction");
}
transaction.Commit();
}
public void Rollback()
{
if (transaction.IsActive)
{
transaction.Rollback();
}
}
public void Dispose()
{
if (session.IsOpen)
{
session.Close();
}
}
}
I am using
- nhibernate + fluent nhibernate
- asp.net mvc 3
- ninject
Currently I am using nhibernate, ninject with the repository pattern and service layers.
So I have this
ninject
public class NhibernateSessionFactory
{
public ISessionFactory GetSessionFactory()
{
ISessionFactory fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Framework.Data.Mapping.TableAMap>().Conventions.Add(ForeignKey.EndsWith("Id")))
.ExposeConfiguration(cfg => cfg.SetProperty("adonet.batch_size", "20"))
.ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"))
//.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
return fluentConfiguration;
}
private static void BuidSchema(NHibernate.Cfg.Configuration config)
{
new NHibernate.Tool.hbm2ddl.SchemaExport(config).Create(false, true);
}
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope()
.OnActivation(StartTransaction)
.OnDeactivation(CommitTransaction);
}
public void CommitTransaction(ISession session)
{
if (session.Transaction.IsActive)
{
session.Transaction.Commit();
}
}
public void StartTransaction(ISession session)
{
if (!session.Transaction.IsActive)
{
session.BeginTransaction();
}
}
}
So I make my nhibernate session factory once for the lifetime of the application then I use it give me sessions when I need it.
One Start of transaction I start a transaction and at the end I close the transaction.
The reason why I did this was because when I was using the nhibernate profiler I would get alot of warnings about using implicit transactions This sort of put a bandaid on the problem but never really fixed it(it cut down the number but anything lazy loaded still got this problem).
an example repo
public class CalendarRepo : ICalendarRepo
{
private readonly ISession session;
public CalendarRepo(ISession session)
{
this.session = session;
}
public List<CalendarAppointment> RepeatingAppointments(int repeatingId)
{
List<CalendarAppointment> calendarAppointments = session.Query<CalendarAppointment>().Where(x => x.RepeatingId == repeatingId && x.RepeatingId != 0)
.Take(QueryLimits.Appointments)
.ToList();
return calendarAppointments;
}
}
service layer
public class CalendarService : ICalendarService
{
private readonly ICalendarRepo calendarRepo;
public CalendarService(ICalendarRepo calendarRepo)
{
this.calendarRepo = calendarRepo;
}
// normally would return something and take in params
public void SampleServiceMethod()
{
// do some checks if needed
// call up the repository
// call commit
// done.
}
}
So that is basically what I have.
I would like to use the unit of work pattern so I get more things commiting and do things properly with the transactions(as right now I been told that I am doing them not quite right)
So I am looking for a simple example on how to get them all to work together and find out how much I need to change of what I got so far.
Most of the tutorials I seen are more complex then I would like. Most do TDD and make generic repositories what is good but before I get to that stage I would like to see a tutorial that does thing simply even if it is repeating code.
Edit
So I been playing around with it and came up with this very very simple example. I am not sure if I am doing it right.
Ninject
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
kernel.Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
kernel.Bind<ITable1Repo>().To<Table1Repo>();
kernel.Bind<ITable1Service>().To<Table1Service>();
kernel.Bind<IUnitofWork>().To<UnitofWork>();
}
The nhibernate factory class is shown in orginal post.
// Controller
public class Default1Controller : Controller
{
private readonly ITable1Service table1Service;
//
// GET: /Default1/
public Default1Controller(ITable1Service table1Service)
{
this.table1Service = table1Service;
}
public ActionResult Index()
{
table1Service.Save();
return View();
}
}
// domain
public class Table1
{
public virtual int Id { get; private set; }
public virtual string C1 { get; set; }
public virtual string C2 { get; set; }
}
// Fluent Mapping
public class Table1Mapping : ClassMap<Table1>
{
public Table1Mapping()
{
Id(x => x.Id);
Map(x => x.C1);
Map(x => x.C2);
}
}
//Repo
public class Table1Repo : unitofwork.Models.Repository.ITable1Repo
{
private readonly ISession session;
public Table1Repo(ISession session)
{
this.session = session;
}
public void Create(Table1 tbl1)
{
session.Save(tbl1);
}
}
// service layer
public class Table1Service : unitofwork.Models.Service.ITable1Service
{
private readonly ITable1Repo table1Repo;
private readonly IUnitofWork unitOfWork;
public Table1Service(ITable1Repo table1Repo, IUnitofWork unitOfWork)
{
this.table1Repo = table1Repo;
this.unitOfWork = unitOfWork;
}
public void Save()
{
Table1 a = new Table1();
a.C1 = "test";
a.C2 = "test2";
table1Repo.Create(a);
unitOfWork.Commit();
}
}
// Unit of work
public class UnitofWork : unitofwork.Models.IUnitofWork
{
private readonly ITransaction transaction;
private readonly ISession session;
public UnitofWork(ISession session)
{
this.session = session;
session.FlushMode = FlushMode.Auto;
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don't have an active transaction");
}
transaction.Commit();
}
public void Rollback()
{
if (transaction.IsActive)
{
transaction.Rollback();
}
}
public void Dispose()
{
if (session.IsOpen)
{
session.Close();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我使用“普通”ASP.NET,而不是 ASP.NET MVC 3,但本质上我们正在做相同的事情。
首先,我有一个单独的
UnitOfWork
类,如下所示:我使用 HTTP 模块为每个 Web 请求启动一个新的工作单元,并自动提交/回滚。不确定使用 ASP.NET MVC 3 时是否需要 HTTP 模块,或者是否有其他方法可以实现。无论如何,相关部分如下所示:
因此,每个 Web 请求都会启动一个新的工作单元,如果没有未处理的异常,则会自动提交。当然,如果需要,您可以在 Web 请求中手动调用
UnitOfWork.Commit()
或UnitOfWork.Rollback()
。StandardIoCSetup.Initialise...
行使用 Ninject 模块配置 NHibernate,与您已经做的非常相似。因此,从本质上讲,向已有的工作单元添加一个工作单元并不需要太多工作。
I'm using 'vanilla' ASP.NET, rather than ASP.NET MVC 3, but essentially we are doing the same things.
First off, I have a seperate
UnitOfWork
class like this:I use an HTTP module to start a new unit of work for every web request, and to automatically commit/rollback. Not sure if you need an HTTP module when using ASP.NET MVC 3, or if there is some other way of doing it. Anyway, relevant parts shown below:
So a new unit of work is started for every web request, and automatically committed if there are no unhandled exceptions. Of course, you can manually call
UnitOfWork.Commit()
orUnitOfWork.Rollback()
within a web request, if required. The lineStandardIoCSetup.Initialise...
configures NHibernate using a Ninject module, much the same as you are already doing.So in essence, it's not much work to add a unit of work to what you already have.