Hibernate session / transaction design - nhibernate

I'm trying to figure out how to best use Sessions in (N)Hibernate. I have a C# remoting object (MarshalByRefObject) which gets consumed by an ASP.NET client.
Currently my remoting class opens up one Session instance in the constructor and uses that one for all transactions. Is this a good idea? And would I need a finalizer for the remote object where session.Dipose() gets called?
Each client request opens a new transaction. Now my database access looks generally like this:
ITransaction transaction = this.session.BeginTransaction();
try {
// perfrom nhibernate query
transaction.Commit();
}
catch (Exception ex) {
transaction.Rollback();
this.session.Flush();
}
and then I often return the retrieved database object to the client.
Is this a valid way to handle this? Should I use the transaction object in a using block or call Dispose() on it? Is the session.Flush() needed after the rollback?
Also sometimes I have a problem when binding a returned collection to a GridView. It throws a exception stating that a binding property of a certain object is not valid. Is this related to hibernate returning proxy objects? And why are the collected objects by hibernate within one query a mixture of "real" and proxy objects?
Thanks!

See my answer here: NH Request Per Session - “Session is closed!”

Related

How to facilitate lazy loading in Nhibernate while i am using Disposable approach?

Currently I am developing the repository for my application, lazy loading give me a great performance push, However its not possible while i am using code block like this
public IList<T> GetAll()
{
using (var session = SessionFactory.OpenSession())
{
try
{
return new List<T>(session.QueryOver<T>().Future());
}
catch (HibernateException)
{
throw;
}
finally
{
session.Flush();
}
}
}
since the session is disposed after i finish, i will receive lazy loading exception when I try to read the references of my objects in the code.
My questions are:
What is the importance of the using block (using (var session = factory.OpenSession)),
why its a bad practice to use single session for all the methods in the repository without flushing it?
Is it possible to use lazy loading with the using block ?
Thanks
What is the importance of a using block ?
Ref : http://msdn.microsoft.com/en-us/library/yh598w02.aspx
The using statement calls the Dispose method on the object in the
correct way, and (when you use it as shown earlier) it also causes the
object itself to go out of scope as soon as Dispose is called. Within
the using block, the object is read-only and cannot be modified or
reassigned.
The Session object returned by .OpenSession() implements IDisposable
Why is it a bad practise to use single session for all methods in the repository without flushing it ?
Is it possible to use lazy loading with the using block ?
I don't quite understand the latter part of the question here, Session in NHibernate is considered as a unit of work and you I believe you need to pick choose a suitable contextual session pattern.
session per thread
session per request (in case of web application)
session per conversation
Reference: http://nhibernate.info/blog/2011/03/02/effective-nhibernate-session-management-for-web-apps.html

WCF and NHibernate transaction scope

I have client calls coming in to WCF Service and then through Fluent NHibernate querying the db.
At the moment WCF is left as it's default (i.e., per call).
And in my code I do something like this:
using (_repository.DbContext.BeginTransaction()) {
try {
_repository.SavePerson(object);
_repository1.SaveAddress(object1);
} catch {
_repository.DbContext.RollbackTransaction();
throw;
}
}
since DbContext is the same for both _repository and _repository1. Do I need to do a RollBack on _repository1?
Also now since the Save methods in the repositories,
the Session object is used to save the objects.
What I need to know is,
is this Session the same for both calls, or are they 2 different ones? I am assuming they to be the same since
I am grouping them in transaction scope as one unit of work.
Also How does this coordinate with WCF calls, do I need to handle transactions from WCF side as well?
Your question can not be answered by someone who does not have access to your code. NHibernate session are not created by WCF, you do have some custom code for creating a session. If you want do stuff to r1 and r2 at the same time and rollback only r1, you need to have to sessions with a transaction on each session. Now you can rollback r1 without touching r2.
The solution is to open a second session from your session factory.

NHibernate + WCF + Windows Service and WcfOperationSessionContext class

I have a Windows Service Application
in which i create WCF services in it.
One of the services is data
services: add, delete,
read , updatte data via
WCF.
WCF use NHibernate for data manipulation
So my guestions are:
Any advice (best practice) for session management for Hibernate using with WCF?
Anybody knows anything about
WcfOperationSessionContext (hibernate 3.0) class?
how to use it with WCF?
Well to make it concrete :
Suppose that i have WCF Service called DataServices
class WCFDataService .....
{
void SaveMyEntity(MyEntity entity)
{
.....................?? // How to do? Best Way
// Should i take one session and use it all times
// Should i take session and dipsose when operation finished then get
//new session for new operations?
// If many clients call my WCF service function at the same time?
// what may go wrong?
// etc....
}
}
And I need a NHibernateServiceProvider class
class NHibernateServiceProvider ....
{
// How to get Session ?? Best way
ISession GetCurrentSession(){.... }
DisposeSession(){ ....}
}
Best Wishes
PS: I have read similiar entries here and other web pages. But can not see "concrete" answers.
The WcfOperationSessionContext, similar to ThreadStaticSessionContext and WebRequestSessionContext is an implementation for a session context. The session context is used to bind (associate) a ISession instance to a particular context.
The session in the current context can be retrieved by calling ISessionFactory.GetCurrentSession().
You can find more information about session context here.
The WcfOperationSessionContext represents a context that spans for the entire duration of a WCF operation. You still need to handle the binding of the session in the begining of the operation and the unbinding/commiting/disposal of the session at the end of the operation.
To get access to the begin/end actions in the wcf pipeline you need to implement a IDispatchMessageInspector. You can see a sample here.
Also regarding WCF integration: if you use ThreadStatic session context it will appear to work on development, but you will hit the wall in production when various components (ex: authorization, authentication ) from the wcf pipeline are executed on different threads.
As for best practices you almost nailed it: Use WcfOperationSessionContext to store the current session and the IDispatchMessageInspector to begin/complete your unit of work.
EDIT - to address the details you added:
If you configured WcfOperationSessionContext and do the binding/unbinding as i explained above, all you have to do to is inject the ISessionFactory into your service and just use factory.GetCurrentSession(). I'll post a sample prj if time permits.
Here is the sample project
The model we use for managing NHibernate sessions with WCF is as follows:
1) We have our own ServiceHost class that inherits from System.ServiceModel.ServiceHost which also implements ICallContextInitializer. We add the service host instance to each of the operations in our service as follows:
protected override void InitializeRuntime()
{
base.InitializeRuntime();
foreach (ChannelDispatcher cd in this.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
{
op.CallContextInitializers.Add(this);
}
}
}
}
public void AfterInvoke(object correlationState)
{
// We don't do anything after the invoke
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
OperationContext.Current.Extensions.Add(new SessionOperationContext());
return null;
}
The BeforeInvoke simply makes sure that the OperationContext for each WCF call has it's own session. We have found problems with IDispatchMessageInspector where the session is not available during response serialisation - a problem if you use lazy loading.
2) Our SessionOperationContext will then be called to attach itself and we use the OperationCompleted event to remove ourselves. This way we can be sure the session will be available for response serialisation.
public class SessionOperationContext : IExtension<OperationContext>
{
public ISession Session { get; private set; }
public static SessionOperationContext Current
{
get
{
OperationContext oc = OperationContext.Current;
if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
return oc.Extensions.Find<SessionOperationContext>();
}
}
public void Attach(OperationContext owner)
{
// Create the session and do anything else you required
this.Session = ... // Whatever instantiation method you use
// Hook into the OperationCompleted event which will be raised
// after the operation has completed and the response serialised.
owner.OperationCompleted += new EventHandler(OperationCompleted);
}
void OperationCompleted(object sender, EventArgs e)
{
// Tell WCF this extension is done
((OperationContext)sender).Extensions.Remove(this);
}
public void Detach(OperationContext owner)
{
// Close our session, do any cleanup, even auto commit
// transactions if required.
this.Session.Dispose();
this.Session = null;
}
}
We've used the above pattern successfully in high-load applications and it seems to work well.
In summary this is similar to what the new WcfOperationSessionContext does (it wasn't around when we figured out the pattern above;-)) but also overcomes issues surrounding lazy loading.
Regarding the additional questions asked: If you use the model outlined above you would simply do the following:
void SaveMyEntity(MyEntity entity)
{
SessionOperationContext.Current.Session.Save(entity);
}
You are guaranteed that the session is always there and that it will be disposed once the WCF operation is completed. You can use transactions if required in the normal way.
Here is a post describing, in detail, all the steps for registering and using the WcfOperationSessionContext. It also includes instructions for using it with the agatha-rrsl project.
Ok, after few days of reading internet posts etc. all approaches shown in the internets seems to be wrong. When we are using UnitOfWork pattern with NH 3^ with nhibernate transaction this all aprochaes are producing exceptions. To test it and proof that we need to create test enviroment with MSMQ transaction queue, special interface with OneWay operation contract with transaction required set on it. This approach should works like this:
1. We put transactionally message in queue.
2. Service is getting transactionally messege from queue.
3. Everything works queue is empty.
In some cases not so obious with internet approaches this does not work properly. So here are expamples which we tested that are wrong and why:
Fabio Maulo approach: Use ICallContextInitializer - open NH session/transaction on BeforeCall, after that WCF is executing service method, on AfterCall in context initializer we call session.Flush + transaction.commit. Automaticly session will be saved when transaction scope will commit operation. In situation when on calling transaction.Complete exception will be thrown WCF service will shutdown! Question can be ok, so take transaction.Complete in try/catch clausule - great! - NO wrong! Then transaction scope will commit transaction and message will be taken from queue but data will not be saved !
Another approach is to use IDispatchMessageInspector - yesterday I thought this is best approach. Here we need to open session/transaction in method AfterReceiveRequest, after WCF invoke service operation on message dispatcher inspector BeforeSendReply is called. In this method we have info about [reply] which in OneWay operation is null, but filled with fault information if it occured on invoking service method. Great I thought - this is this ! but NOT! Problem is that at this point in WCF processing pipe we have no transaction ! So if transaction.Complete throw error or session.Flush will throw it we will have not data saved in database and message will not come back to queue what is wrong.
What is the solution?
IOperationInvoker and only this!
You need to implement this interface as a decorator pattern on default invoker. In method Invoke before call we are openning session/transaction open then we call invoke default invoker and after that call transaction.complete in finally clausule we call session.flush. What types of problem this solves:
1. We have transaction scope on this level so when complete throws exception message will go back to queue and WCF will not shutdown.
2. When invocation will throw exception transaction.complete will not be called what will not change database state
I hope this will clear everyones missinformation.
In some free time I will try to write some example.

Entity Framework and WCF (Returning Entities Attached To Context)

I have a WCF service that calls the following method in one of my Repository objects to create a new sale object in the database
public static Sale New(Sale sale)
{
using (var ctx = new DBcontext())
{
ctx.Sales.AddObject(sale);
ctx.SaveChanges();
return sale;
}
}
The WCF method calling this looks like this
public Sale SaleNew(Sale sale)
{
return SaleRepository.New(sale);
}
When I call this from a client application I get the following error
"The underlying connection was closed: The connection was closed unexpectedly."
If I step through all the code seems to run fine and the record gets insterted into the database. If I add the following line to my repository method after the SaveChanges it works fine
ctx.Detach(sale);
Is the exception happening because I'm disposing the context as soon as the method returns? Is using the entity context in this way bad practise ie disposing of it straight away? I'm only doing this because its SOA and pretty much stateless so all my repository methods create the context return the value and dispose the context. Anything that is passed in will either get added to the context or re-attached.
As advised I turned on tracing in WCF and watched what was happening. There was a proxy exception occurring. In this case as I'm using my own POCO objects I don't really want proxy objects so I set the ContextOptions.ProxyCreationEnabled property in my DatabaseContext to false and it now works fine.
1) Is using the entity context in this way bad practise ie disposing of it straight away?
No, that's how I do it - and I believe it is the proper way of doing it. But creating context can be expensive and with EF we are stuck with no ideal way of reusing the context.
2) ctx.Detach(sale);
This as far as I know should not be required for what you are doing although I have had loads of issues with attaching and detaching when I reuse the same entities. This should be only needed if you need to re-attach to context. Are you using Lazy-Loading?

Handling Start Up Issues With NHibernate In Global.asax

I have a WCF Service, hosted inside of IIS, using NHibernate for data access.
In my Global.asax I configure NHibernate on Application_Start. This means that I only perform the expensive task of setting up all of the mappings once for my WCF Service.
The only problem with this is that if the database was unavailable during start up, the mappings will never get set up (as they will have failed to be set up during Application_Start and the event won't be called again until the app pool is recycled).
How can I handle the NHibernate set up so it occurs only once, except where there is an error (such as the database not being available) in which case it will occur on each request until it works?
What you need is a Lazy Singleton to be your SessionFactory. You call a method to get the session factory and it checks if the session already exists. So the expensive task of creating the Session Factory is done the first time someone needs it.
You could do something like this:
public ISessionFactory GetSessionFactory()
{
// sessionFactory is STATIC
if (sessionFactory == null)
{
global::NHibernate.Cfg.Configuration cfg = new NHibernateConfigurationFactory(CurrentConfiguration).GetConfiguration(sessionFactoryName);
// Now that we have our Configuration object, create a new SessionFactory
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new InvalidOperationException("cfg.BuildSessionFactory() returned null.");
}
}
return sessionFactory;
}
A complete solution is available here:
NHibernate - good complete working Helper class for managing SessionFactory/Session
I am throwing this answer into the mix in order to get comments on it - this answer was emailed to me, but I'd appreciate the view of the SO community before I decide on the final solution...
Rather than using the Application_Start event, use the Begin_Request event. Store the NHibernate session in a field and in the Begin_Request event, check if the field is null and if it is, create the NHibernate session (otherwise, continue to use the one already created).
So essentially, this would mean moving the create logic into a method I can call from Begin_Request in the event of "detecting that the session hasn't yet been created".