需要一個簡單的使用nhibernate + 工作單元+ 儲存庫模式+ 服務層+ ninject 的例子
我在用
- nhibernate + 流利的 nhibernate
- asp.net mvc 3
- 注射
目前我正在使用帶有儲存庫模式和服務層的 nhibernate、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 探查器時,我會收到很多關於使用隱式事務的警告 這種對問題進行了創可貼,但從未真正解決它(它減少了數量,但仍然載入了任何懶惰的東西遇到這個問題)。
一個範例回購
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 並製作通用儲存庫什麼是好的,但在我進入那個階段之前,我希望看到一個教程,即使它是重複程式碼,它也能簡單地做事。
編輯
所以我一直在玩它並想出了這個非常簡單的例子。我不確定我是否做得對。
忍者
/// <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; } }// 流暢的映射
public class Table1Mapping : ClassMap<Table1> { public Table1Mapping() { Id(x => x.Id); Map(x => x.C1); Map(x => x.C2); } }//回購
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(); } } }
我使用的是’vanilla’ ASP.NET,而不是 ASP.NET MVC 3,但本質上我們正在做同樣的事情。
首先,我有一個
UnitOfWork像這樣的單獨課程:public class UnitOfWork { private static ISessionFactory SessionFactory { get { return Container.Get<ISessionFactory>(); } } public static ISession Session { get { return SessionFactory.GetCurrentSession(); } } public static void Start() { CurrentSessionContext.Bind(SessionFactory.OpenSession()); Session.FlushMode = FlushMode.Commit; Session.BeginTransaction(IsolationLevel.ReadCommitted); } public static void Rollback() { Rollback(true); } /// <summary> /// Rollback the current transaction, and optionally start a new transaction /// </summary> /// <param name="startNew">Whether to start a new transaction and keep the session open</param> public static void Rollback(bool startNew) { ISession session = CurrentSessionContext.Unbind(SessionFactory); if (session != null) { // Rollback current transaction if (session.Transaction.IsActive && !session.Transaction.WasRolledBack) { session.Transaction.Rollback(); } // Close and discard the current session session.Close(); session.Dispose(); session = null; } if (startNew) { Start(); } } /// <summary> /// Commit the current transaction, keeping the current session open and starting a new transaction /// /// Call Commit multiple times during a single unit of work if you want to commit database changes in /// multiple transactions /// </summary> public static void Commit() { Commit(true); } /// <summary> /// Commit the current transaction, and optionally keep the session open and start a new transaction /// /// Call Commit multiple times during a single unit of work if you want to commit database changes in /// multiple transactions /// </summary> /// <param name="startNew">Whether to start a new transaction and keep the session open</param> public static void Commit(bool startNew) { if (startNew) { Session.Transaction.Commit(); Session.BeginTransaction(IsolationLevel.ReadCommitted); } else { ISession session = CurrentSessionContext.Unbind(SessionFactory); if (session != null) { if (session.Transaction.IsActive && !session.Transaction.WasRolledBack) { session.Transaction.Commit(); } session.Close(); session.Dispose(); session = null; } } } }我使用 HTTP 模組為每個 Web 請求啟動一個新的工作單元,並自動送出/回滾。不確定在使用 ASP.NET MVC 3 時是否需要 HTTP 模組,或者是否有其他方法。無論如何,相關部分如下所示:
public class IoCHttpModule : IHttpModule, IDisposable { private HttpApplication httpApplication; public void Init(HttpApplication context) { if (context == null) throw new ArgumentException("context"); this.httpApplication = context; this.httpApplication.BeginRequest += new EventHandler(BeginRequest); this.httpApplication.EndRequest += new EventHandler(EndRequest); this.httpApplication.Error += new EventHandler(Error); StandardIoCSetup.Initialise(SessionContextType.Web); } private void BeginRequest(object sender, EventArgs e) { UnitOfWork.Start(); } private void EndRequest(object sender, EventArgs e) { UnitOfWork.Commit(false); } private void Error(object sender, EventArgs e) { UnitOfWork.Rollback(false); } public void Dispose() { if (this.httpApplication == null) return; this.httpApplication.Dispose(); } }因此,每個 Web 請求都會啟動一個新的工作單元,如果沒有未處理的異常,則會自動送出。當然,如果需要,您可以手動呼叫
UnitOfWork.Commit()或UnitOfWork.Rollback()在 Web 請求中呼叫。該行StandardIoCSetup.Initialise...使用 Ninject 模組配置 NHibernate,與您已經在做的非常相似。所以從本質上講,在你已經擁有的東西上添加一個工作單元並不是什麼工作。