How to speed up my Nhibernate configuration - fluent-nhibernate

I have a ASP.NET MVC4 web api that uses fluent NHibernate, but when I run debug it takes 1½ min to access any site that uses the database the first time I try, so I found Fluent nHibernate Slow Startup Time but I am not sure how to utilize that,
When it runs on the live server it must garbage collect the session data as it takes ages to configure again if I havent used it for a long time.
Is it possiible to cut it down to maybe sub 10 seconds instead of 1.5 minutes?
My current SessionFactory class looks like this
public class SessionFactory
{
private static readonly string ConnString = System.Configuration.ConfigurationManager.ConnectionStrings["MySQLConnectionString"].ConnectionString;
private static ISessionFactory _session;
private static readonly object SyncRoot = new Object();
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MySQLConfiguration
.Standard
.ConnectionString(ConnString))
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<UserMap>())
.ExposeConfiguration(UpdateSchema)
.BuildSessionFactory();
}
private static void UpdateSchema(Configuration cfg)
{
new SchemaUpdate(cfg).Execute(false, true);
}
public static ISession Session
{
get
{
if (_session == null)
{
lock (SyncRoot)
{
if (_session == null)
_session = CreateSessionFactory();
}
}
return _session.OpenSession();
}
}
}
Here is a screenshot of a dotTrace
Timing the request on my host it takes 1 min and 50 seconds for the initial request, and thats on "live" server (I cant control the IIS there)

I can see a host of things wrong with this code. Your CreateSessionFactory should only ever be called once in the lifetime of your application. Create a static variable in global.asax and call CreateSessionFactory once in Application_Start(). Also in global.asax, you want to setup some events for Application_BeginRequest and Application_EndRequest. This is where you are going to create and destory sessions. This is your unit of work in a web application. You should also store your session in the HttpContext.
public static ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items[sessionkey]; }
set { HttpContext.Current.Items[sessionkey] = value; }
}
protected void Application_BeginRequest()
{
CurrentSession = SessionFactory.OpenSession();
}
protected void Application_EndRequest()
{
if (CurrentSession != null)
CurrentSession.Dispose();
}
Your code recreates the SessionFactory every time you need a session.

Related

NHibernate TransactionService implemenation example

I keep getting the following message while retrieving my domain objects:
failed to lazily initialize a collection of role no session or session was closed
I know the problem has something to do with lazy loading of the collection on my domain object and i'm trying to fix this, but it would be nice if someone could point me in the right direction. The problem is that i have a using statement on my session object and i would like to get rid of the sessions in my repository classes.
Stefan Steinegger recommended to use a TransactionService wich manages the transactions in the following post:
C# Shared Transactions and NHibernate using IRepository
It would be nice someone can provide a tutorial, example on how to implement such a service.
There's a few different ways that you can handle this within a web application and probably the most common in web applications is a Session Per Web Request.
Inside of Application_Start in global.asax.cs, create the SessionFactory and assign it to a static property:
public static ISessionFactory SessionFactory { get; private set; }
protected void Application_Start(object sender, EventArgs e)
{
// your configuration setup
var configuration = new NHibernate.Cfg.Configuration().Configure();
SessionFactory = configuration.BuildSessionFactory();
}
Then, in Application_BeginRequest in global.asax.cs, open a session using the SessionFactory and bind it to the CurrentSessionContext
protected void Application_BeginRequest(object sender, EventArgs e)
{
var session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
}
and in Application_EndRequest in global.asax.cs, unbind the session and dispose of it
protected void Application_EndRequest(object sender, EventArgs e)
{
var session = CurrentSessionContext.Unbind(SessionFactory);
session.Dispose();
}
Now inside of the application, whenever a session is required, we simply ask the SessionFactory for the current session
public class HomeController : Controller
{
public ActionResult Index()
{
IEnumerable<Product> products = null;
var session = MvcApplication.SessionFactory.GetCurrentSession();
using (var transaction = session.BeginTransaction())
{
// your query, which sounds like it should also eager load
// a child collection
products = session.QueryOver<Product>().List();
transaction.Commit();
}
return View(products);
}
}
There are numerous variations on this, including using a LazySessionContext to lazily create a session only if one is needed for a request, and implementations where ISessionFactory could be injected into you controllers through dependency injection.

NHibernate Repository class - 1. Handle with Transaction | 2. How init session

Hi I start learn NHibernate and now I am trying create own repository class for NHibernate.
I found many articles about this thema. I chose this tutorial: http://dotnetslackers.com/Community/blogs/antrad/archive/2008/10/25/about-repository-pattern-and-nhibernate.aspx
I am little confuse how handle with transaction in repository.
I have repository interface:
public interface IRepository<T> where T : class
{
void Commit();
void RollBack();
void BeginTransaction();
//...
}
My question is why is good begin transaction in constructor class of repository.
This part of code is from blog on top.
public class NHibRepository<T> :IRepository<T>
where T : class
{
#region Private fields
private ISession _session;
#endregion
#region Constructor
public NHibRepository(ISession session)
{
_session = NHibernateSessionManager.Instance.GetSession();
//why begin transaction where???
_session.BeginTransaction();
}
#endregion
#region Trans
public void Commit()
{
if (session.Transaction.IsActive)
{
session.Transaction.Commit();
}
}
public void Rollback()
{
if (session.Transaction.IsActive)
{
session.Transaction.Rollback();
session.Clear();
}
}
public void BeginTransaction()
{
Rollback();
session.BeginTransaction();
}
#endregion
}
I update this repository and now I use this solution:
public class NHibRepository<T> :IRepository<T>
where T : class
{
#region Private fields
private ISession _session;
#endregion
#region Constructor
public NHibRepository(ISession session)
{
_session = session;
}
#endregion
#region Trans
public void Commit()
{
using (var trans=_session.BeginTransaction())
{
trans.Commit();
}
}
public void RollBack()
{
using (var trans = _session.BeginTransaction())
{
trans.Rollback();
}
}
public void BeginTransaction()
{
throw new NotImplementedException();
}
#endregion
}
My first question is which solution is better and why? or what is correct why?
And my second question is how open session for repository class, now I use this helper class:
public class NHibeHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
InitializeSessionFactory();
return _sessionFactory;
}
}
private static void InitializeSessionFactory()
{
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(
#"Server=Zues\SQLEXPRESS;Database=TEST;Trusted_Connection=True;")
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>().Conventions.Add(DefaultCascade.All()))
.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(true, true))
.BuildSessionFactory();
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
On use like this:
_userRepo = new NHibRepository<User>(NHibeHelper.OpenSession());
Looking at the two options you've presented for transaction management, they both actually have issues.
In example 1, the transaction isn't necessarily disposed, and also you're linking the lifetime of the transaction to the lifetime of the repository. This isn't necessarily a bad thing but unless you're using an IoC container or some other method to ensure that the repository is recreated for each database operation, you will only be able to commit once, and subsequent commits will probably fail.
Example 2 will unfortunately not work at all - in Commit/RollBack you are starting a new transaction every time. Especially in the case of RollBack, if this was called from external code while in the context of a transaction, all you will do is start a new nested transaction and then immediately roll it back. Not very useful unfortunately.
My personal solution to your first question is to pull transaction management away from the repository by using the ambient transactions in System.Transactions. This way you still have separation as ambient transactions are provider-agnostic, but also you have more control about what of many repository operations you might be performing will be involved in the transaction, rather than always using the single-transaction-per-operation model. See http://msdn.microsoft.com/en-us/magazine/cc163527.aspx for more info.
As for your second question, I would highly recommend looking into an IoC container like Castle Windsor or Unity. The helper class you have there is far better than rebuilding the session factory and such every time, but by using an IoC container you can very easily ensure the lifetime of your session object is exactly what you want it to be. For instance, in a number of WCF Per-Call services I'm working on, I use Castle Windsor to ensure that the session is created (and injected into the repository) when the WCF operation begins, and is disposed (along with the repository) when it ends.

nhibernate : Repository Session Management

At the moment my repository has 2 constructors. When i call these from my mvc website i am alway calling first constructor and thus opening a new session. Should i been passing in the session. How should i be doing this.
public CompanyRepository()
{
_session = NHibernateHelper.OpenSession();
}
public CompanyRepository(ISession session)
{
_session = session;
}
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(UserProfile).Assembly);
configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
System.Environment.MachineName);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
I'm using the Ninject IOC container ( very new to me ). I have the following container. How would i bind the ISession to the CompanyRepository.
private class EStoreDependencies : NinjectModule
{
public override void Load()
{
Bind<ICompanyRepository>().To<CompanyRepository>();
Bind<IUserProfileRepository>().To<UserProfileRepository>();
Bind<IAddressRepository>().To<AddressRepository>();
Bind<IRolesService>().To<AspNetRoleProviderWrapper>();
Bind<IUserService>().To<AspNetMembershipProviderWrapper>();
Bind<ICurrentUserSerivce>().To<DefaultCurrentUserSerivce>();
Bind<IPasswordService>().To<AspNetMembershipProviderWrapper>();
Bind<IStatusResponseRepository>().To<StatusResponseRepository>();
Bind<ICategoryRepository>().To<CategoryRepository>();
Bind<IProductRepository>().To<ProductRepository>();
}
}
You should be using the "one session per request" pattern, by storing the ISession object in the HttpContext and sharing it between repositories and queries made during the same HTTP request.
Here's an implementation using MVC action attributes.
An easy/basic implementation could also be achieved by simply altering your NHibernateHelper class like this:
public class NHibernateHelper {
//...
const string SessionKey = "NhibernateSessionPerRequest";
public static ISession OpenSession(){
var context = HttpContext.Current;
if(context != null && context.Items.ContainsKey(SessionKey)){
//Return already open ISession
return (ISession)context.Items[SessionKey];
}
else{
//Create new ISession and store in HttpContext
var newSession = SessionFactory.OpenSession();
if(context != null)
context.Items[SessionKey] = newSession;
return newSession;
}
}
}
Code hasn't been neither compiled nor tested... should work however.
Your code or, preferably, dependency injection should always pass the ISession into a repository's constructor. This allows multiple repositories to participate in a single transaction.
I second Paco's recommendation to let a dependency injection framework handle this for you. The challenge with this approach is with non-web applications that do not have clean unit-of-work boundaries like the HTTP request-response cycle. We have repositories that are shared by Windows Forms and ASP.NET applications and we manually manage newing up repositories in the Windows Forms applications.
Use an inversion of control container
Try using sessionFactory.GetCurrentSession() which will allow you to access a contextual session.
This will basically allow you to use the 'session per request' model as described in another answer, without having to code that yourself.
You can even choose what your context is: Http (as your example suggests) or a bunch of others too (I use CallSessionContext for my unit test).

What if building Nhibernate session factory fails?

I'm currently creating a system which in some cases, if the database is not available, uses a MSMQ instead. E.g. if the application (in one of the cases it's a wcf web service) starts, and the database is not available, all incoming requests should be written to the MSMQ. When the database is available again, the requests should be written to the db again.
I am using NHibernate and the session factory is wrapped by a singleton. This is what the service looks like:
try
{
// to database (just an example)
SessionProvider.Current.CurrentSession.Save...
}
catch(NHibernate.ADOException)
{
// to msmq
}
This setup works when the service is up and running for some time and the session factory has been build. When stopping the SQL server ADO exceptions are raised and things are written to the MSMQ properly.
Now my problem. If the database is not available BEFORE the service is started the first time, the session factory cannot be build and a TypeInitializationException is thrown. My singleton session provider is now broken. So when the database is running again, I somehow need a way to rebuild the session factory. Would I do that timer based? Like trying to rebuild it every 5 minutes? How can I 'reinstantiate' a singleton?
Here's an excerpt of the session provider pattern I am using:
public sealed class SessionProvider : ISessionProvider
{
private ISessionFactory sessionFactory;
private SessionProvider()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
public static ISessionFactory SessionFactory
{
get
{
return Nested.SessionProvider.sessionFactory;
}
}
public static ISessionProvider Current
{
get
{
// TypeInitializationException is thrown when building session factory fails
return Nested.SessionProvider;
}
}
private class Nested
{
internal static readonly SessionProvider SessionProvider = new SessionProvider();
}
}
I suggest you change your SessionProvider like this:
...
private ISessionFactory sessionFactory;
private Configuration config;
private SessionProvider()
{
config= new Configuration();
config.Configure();
}
public static ISessionFactory SessionFactory
{
get
{
if(sessionFactory==null)
sessionFactory=config.BuildSessionFactory();
return Nested.SessionProvider.sessionFactory;
}
}
...

How to properly use a NHibernate ISession object - Session Is Closed! errors

I'm running into issues with my ISessions in NHibernate. I keep getting "Session Closed!" errors. Can some one please show me the correct pattern including a definition of the following methods and when to use each:
ISession.Close()
ISession.Dispose()
ISession.Disconnect()
Here's my problem. I have a callback setup to fire off a process that awards badges to players every couple of minutes. However I keep getting "Session Closed!" errors or errors about not being able to associate collections.
Here's my Repository:
public class NHibernateRepository : IRepository
{
#region Fields
private ISession _session;
private readonly ISessionFactory _sessionFactory;
#endregion
#region Constructors
public NHibernateRepository(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
#endregion
#region IRepository Implementation
public ISession OpenSession()
{
_session = _sessionFactory.OpenSession();
return _session;
}
public IQueryable<TModel> All<TModel>()
{
return _session.Linq<TModel>();
}
public void Save<TModel>(TModel model)
{
_session.Save(model);
}
public void Update<TModel>(TModel model)
{
_session.Update(model);
}
public void Delete<TModel>(TModel model)
{
_session.Delete(model);
}
public ITransaction BeginTransaction()
{
return _session.BeginTransaction();
}
public void Flush()
{
_session.Flush();
}
#endregion
}
Here's my usage. The repository is getting injected via Structure Map
private Object _awardBadgesLock = new object(); //In case the callback happens again before the previous one completes
public void AwardBadges()
{
lock (_awardBadgesLock)
{
using(session = _repository.OpenSession())
{
foreach (var user in _repository.All<User>().ToList())
{
var userPuzzles = _repository.All<Puzzle>().ByUser(user.Id).ToList();
var userVotes = _repository.All<Vote>().Where(x => x.UserId == user.Id).ToList();
var userSolutions = _repository.All<Solution>().ByUser(user.Id).ToList().Where(x => !userPuzzles.Select(y => y.Id).Contains(x.PuzzleId));
var ledPuzzles = GetPuzzlesLedByUser(user.Id);
AwardPlayerBadge(user, userSolutions);
AwardCriticBadge(user, userVotes);
AwardCreatorBadge(user, userPuzzles);
AwardRidlerBadge(user, userPuzzles);
AwardSupporterBadge(user, userVotes);
AwardPopularBadge(user, userPuzzles);
AwardNotableBadge(user, userPuzzles);
AwardFamousBadge(user, userPuzzles);
AwardLeaderBadge(user, ledPuzzles);
using (var tx = _repository.BeginTransaction())
{
_repository.Update(user);
tx.Commit();
}
}
}
}
}
You should always use session.Dispose();
The other are for very strange occurances
I advice you to read the documentation of ISession on
https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs
Anyway the proper way to clean up when you are finished with the session is to dispose it (or better, surround the usage with using statement). In this case, "using" closes the session and suppresses the finalizer, i.e. it prevents the session object from unnecessarily surviving the next garbage collecting and saves the memory.
If the connection is already closed, disposing it will not throw an exception. On the other hand, closing after disposing (or after closing) throws an exception.
The documentation recommends calling disconnect instead of closing, because this releases the connection to the connection pool. You should call Reconnect before using a disconnected session.
For my needs, I always use "using" which calls Dispose and have never used the othe two functions.
The issue lies in the fact the ISession is not thread-safe. There were multiple methods being fired on separate threads that all created an instance of ISession. The issue was really with the fact that they all shared the same SessionFactory. Image both of these methods are fired off on separate threads:
ISessionFactory _sessionFactory;
void MethodOne()
{
using(ISession session = _sessionFactory.OpenSession())
{
//Do something with really quick with the session
//Then dispose of it
}
}
void MethodTwo()
{
//OpenSession() actually returns the same instance used in the
//previous method that has already disposed of the object;
using(ISession session = _sessionFactory.OpenSession())
{
//Do something with a session that has already been disposed
//throws errors
}
}
How I fixed it was basically ditching NHIbernate in these scenarios and called stored procs instead. I think it turned out to be more performant in my situation anyway.
About the problem, your method of locking is right as long as you dispose the session but probably the bug lies under another part of your codes. by the way about the design, it is better that you pass the session variable to repositories because of unit of work implementation of the session and aggregate root's transaction like this:
using (ISession session = SessionFactory.OpenSession())
{
Repository1 rep1 = new Repository1(session);
Repository2 rep1 = new Repository2(session);
Repository3 rep1 = new Repository3(session);
// some logics
using (var tx = session.BeginTransaction())
tx.Commit();
}
.
.
.