开发者

Fluent NHibernate ISessionManager or equivilent

I am quite new to the FNH and NH world, so be gentle :P

I have created an application using FNH for data access which works good while not using lazy-loading, however once I enable lazy-loading everything goes pear shaped (as in, no sessions are open when I attempt to access the lazy-loaded properties etc).

The application layout I have created thus-far has a "Database" singlet开发者_如何学Pythonon which has various methods such as Save(), Refer() and List().

When calling Refer() a session is opened, the data is retrieved and the session is disposed; meaning there is no session available when attempting to access a lazy-loaded property from the returned object. Example: Database.Refer("username").Person since Person is lazy-loaded and the session has already closed.

I have read that Castle has a SessionManager that could be used for this very scenario but, either it's the late nights or lack of coffee, I can't seem to work out how to hook up FNH to use this manager as, in the spirit of castle, everything is defined in config files.

Am I missing something, or can this not be done? Are there any other session managers (or even more appropriate conventions) that I should look at?

Thanks for any help on this matter.


I don't think that your particular problem is connected with the SessionManager as you've already mentioned that you are capable of starting a new session and disposing it whenever needed.

From what I can understand of your post is that you are trying to expose an entity to your view (with some lazy-loaded properties) - which is already a bad idea because it leads to nasty LazyInitializationException(s).

You should consider making a distinguishion between your data-model and your domain model. The key concept has been described on this blog:

Ayende @ Rahien http://ayende.com/blog/4054/nhibernate-query-only-properties

If you say that you are writing a very simple 2-tier application then it probably will not harm if you will micro-manage your session in the data-layer (but keep in mind that this is not the best solution).

I would also look into the query that fetches your entity, as it seems to me that your are trying to obtain data that is just a part of your model - in this case Person. This can lead into serious problems like n+1 selects:

What is SELECT N+1?

So in general I think you should focus more on how things are structured in your application instead of searching for a SessionManager as it will not resolve all of your problems.


For any of you who are still looking for answers on this, I will share with you what I have so far.

This is only a very simple overview of the framework that I have decided to use, and is by far not the only solution for this problem.

The basic layout of my code is as follows:

  • NHibernate Repository (references my model assembly and the UoW assembly)
    • Based on the HibernatingRhino's Repository implementation modified to suit my needs. Found here: http://ayende.com/Wiki/Rhino+Commons.ashx
      public T Get(Guid Id)
      {
          return WrapUOW(() =>
          {
              using (Audit.LockAudit())
                  return (T)Session.Get(typeof(T), Id);
          });
      }
      public void LoadFullObject(T partial)
      {
          if (partial == null)
              throw new ArgumentNullException("partial");
      
          if (partial.Id == Guid.Empty)
              return;
      
          WrapUOW(() =>
          {
              using (Audit.LockAudit())
              {
                  LazyInitialiser.InitialiseCompletely(partial, Session);
              }
          });
      }
      public T SaveOrUpdate(T entity)
      {
          using (Audit.LockAudit())
          {
              With.Transaction(() =>
              {
                  Enlist(entity);
      
                  Session.SaveOrUpdate(entity);
      
                  entity.HasChanged = false;
              });
          }
      
          return entity;
      }
      protected void Enlist(T instance)
      {
          if (instance != null && instance.Id != Guid.Empty && !Session.Contains(instance))
              using (Audit.LockAudit())
              {
                  Session.Update(instance);
              }
      }
      
      
    • References a neat little helper class called 'Lazy Initializer for NHibernate' found here: http://www.codeproject.com/KB/cs/NHibernateLazyInitializer.aspx
    • This also contains Extension methods for Save, Delete and LoadFullObject
    • Have broken standards a little in this assembly by also creating a WrapUOW method to help simplify some of my code
      protected static T WrapUOW(Func action)
      {
          IUnitOfWork uow = null;
      
          if (!UnitOfWork.IsStarted)
              uow = UnitOfWork.Start();
      
          T result = action();
      
          if (uow != null)
              uow.Dispose();
      
          return result;
      }
  • NHibernate Unit of work (references my model assembly)
    • Also based on the HibernatingRhino's UoW implementation and modified to suit
  • View - not important, just requried for MVVM implementation
    • Binds the values from the ViewModel
  • Model
    • Contains my entity classes and hibernate mapping files
  • ViewModel
    • Contains two main view base classes, ListPage and MaintenancePage
    • The ListPage base class just calls the Repository List method based on the object type we are listing. This loads a dehydrated list of entities.
    • The MaintenancePage takes an entity instance from the ListPage and calls the Repository.LoadFullObject method to rehydrate the entity for use on the screen.
      • This allows for the use of binding on the screen.
      • We can also safely call the Repository.SaveOrUpdate method from this page
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜