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; }
- Based on the HibernatingRhino's Repository implementation modified to suit my needs. Found here: http://ayende.com/Wiki/Rhino+Commons.ashx
- 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
精彩评论