Dot-Net

需要一個簡單的使用nhibernate + 工作單元+ 儲存庫模式+ 服務層+ ninject 的例子

  • September 9, 2011

我在用

  • 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,與您已經在做的非常相似。

所以從本質上講,在你已經擁有的東西上添加一個工作單元並不是什麼工作。

引用自:https://stackoverflow.com/questions/7113245