NHibernate many to many and ISession.Close() - nhibernate

I am using NHibernate for my project. i am quite a beginner at working on NHibernate.
I use many-to-many relation mapping "users" and "roles". Here is the code to get the user:
public User GetUser(int userId){
using(ISessuib session = new SessionManager().GetSession())
{
return session.Get<User>(userId);
}
}
public void LazyLoadUsingSessionTest(){
var user= GetUser(1);
Assert.NotNull(user.Roels);
}
it throws an exception:failed to lazily initialize a collection, no session or session was closed
if i do not use the "using" statement in the "GetUser" method,it works. But i must call the session.Close() to release the resource
when i use it in a web page,i only want to use the GetUser(), not the ISession object.so my question is : Does it mean that i must have a ISession object(to release resouse) in my web page? or any better solution?(because i do not want the ISession object appears in my aspx.cs files)
thanks!

You need to use the Session per Request pattern. See this link for an explanation of the best practices for using NHibernate with ASPX.

The simplest way is to use NHibernateUtil.Initialize (read here for details):
using(ISession session = new SessionManager().GetSession())
{
User user = session.Get<User>(userId);
NHibernateUtil.Initialize(user.Roles);
return user;
}
However, sooner or later you would need to somehow manage the sessions in your application. I recommend creating a data provider layer that would give you access to the database. The data provider layer will manage the creation and destruction of sessions. You could either have a session per request or per conversation (single ISession for the duration of an ASP.Net session).
The Summer Of NHibernate video series would be helpful. Session 5 and 13 are most relevant for you.

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

Risks of holding an Entity Framework dynamic proxy object in session?

So I have a fairly comprehensive activity-based access control system I built for a web app under MVC 4 using Entity Framework. Well, to be precise the access control doesn't care if it's using EF or not, but the app is.
Anyway, I'm loading the user's permissions on each request right now. I get a reference to my DbContext injected from the IoC container into my ApplicationController, and it overrides OnAuthorization to stuff the user's profile into the HttpContext.Current.Items. Seems to work fairly well, but I can't help but wonder if it's the best way.
My thought was that since the users' permissions don't change often, if ever, the better way to do it would be to load the profile of permissions into the Session instead, and then not have to change them at all until the user logs out and logs back in (pretty common in desktop OS's anyway). But I'm concerned that if I fetch using the DbContext, then the object I get back is a dynamic proxy which holds a reference to the DbContext and I certainly don't want to do that for the whole session.
Thoughts? Is this a good approach, and if so how do I ensure that my DbContext doesn't linger beyond when I really need it?
Invoke .AsNoTracking() on the Set<UserPermission> before you query out. Entities will still be proxied, but will be detached from the DbContext.
var userPermission = dbContext.Set<UserPermission>().AsNoTracking()
.SingleOrDefault(x => x.UserName == User.Identity.Name);
Thoughts? Is this a good approach?
Putting a dynamically proxied entity in session will break as soon as you load balance your code across more than 1 web server. Why? Because of the dynamic proxy class. Server A understands the type DynamicProxies.UserPermission_Guid, because it queried out the entity. However Server B through N do not, and therefore cannot deserialize it from the Session. The other servers will dynamically proxy the entity with a different GUID.
That said, you could DTO your data into a POCO object and put it in session instead. However then you do not need to worry about your entity being attached to the context when you first query it out. AsNoTracking will only make the query perform a bit faster.
// you can still call .AsNoTracking for performance reasons
var userPermissionEntity = dbContext.Set<UserPermission>().AsNoTracking()
.SingleOrDefault(x => x.UserName == User.Identity.Name);
// this can safely be put into session and restored by any server with a
// reference to the DLL where the DTO class is defined.
var userPermissionSession = new UserPermissionInSession
{
UserName = userPermissionEntity.UserName,
// etc.
};
Thoughts? Is this a good approach?
Another problem attached to this approach is when you use the common pattern that create one dbContext per http request. This pattern typically dispose dbContext when the request ends.
protected virtual void Application_EndRequest(object sender, EventArgs e)
But what happen when we try to get navigation property of a proxy entity which reference to a disposed DbContext?
We will get a ObjectDisposedException

RavenDb session management for WCF and integration testing

Put simply, I have a WCF service that manages apples. Apart from other functionality, it has two methods to add and remove apples from storage. I am writing an integration test to check if someone is getting advantage of the job and nicks apples. Raven DB in my WCF service has an audit role, it just records actions and apples. In the methods of WCF service there is some other processing: cleaning, validation, packaging etc.
My audit integration test can be expresses as
Empty storage (RavenDB in-memory mode)
Bob comes and puts 10 apple (open session, add, dispose session)
Jake comes and takes 4 apples (open session, remove, dispose session)
Check that 6 apples left
As these are two different people (two WCF calls) it make sense to use different instances of session. However, with Raven DB I get
Exception
Apple is not associated with the session, cannot delete unknown entity
instance
If I now run similar integration test where two different people just add apples to the storage, the total storage content corresponds to truth. This is confusing bit: adding works across session, removing doesn't work. In this post Ayende says session micro-managing is not the way to go, but it seems natural to me to use different sessions in my integration testing. Hope analogy with apples doesn't put you off.
Question: How do I use sessions in integration testing with RavenDB?
Sample code (from notepad)
public void Remove(Apple apple)
{
using (var session = Store.OpenSession())
{
session.Delete(apple);
session.SaveChanges();
}
}
public void Add(Apple apple)
{
using (var session = Store.OpenSession())
{
session.Store(apple);
session.SaveChanges();
}
}
...
var apples = new apples[10];
//init
MyRavenDB.Add(apples);
MyRavenDB.Remove(apples.Take(4)); //throws here
//verify
In RavenDB, "The session manages change tracking for all of the entities that it has either loaded or stored".
I suspect the Apple reference you are passing to Remove() method, did not originate from RavenDB Document Store, hence the error.
Try this:
public void Remove(Apple apple)
{
using (var session = Store.OpenSession())
{
var entity = session.Load<Apple>(apple.Id);
session.Delete(entity);
session.SaveChanges();
}
}
You are passing entities over the wire, and that is generally a big no-no.
Do it like this:
public void Remove(string appleId)
That would give you much better sematnics.

Single website multiple connection strings using asp mvc 2 and nhibernate

In my website i use ASP MVC 2 + Fluent NHibernate as orm, StructureMap for IoC container.
There are several databases with identical metadata(and so entities and mappings are the same). On LogOn page user fiils in login, password, rememberme and chooses his server from dropdownlist (in fact he chooses database).
Web.config contains all connstrings and we can assume that they won't be changed in run-time.
I suppose that it is required to have one session factory per database.
Before using multiple databases, i loaded classes to my StructureMap ObjectFactory in Application_Start
ObjectFactory.Initialize(init => init.AddRegistry<ObjectRegistry>());
ObjectFactory.Configure(conf => conf.AddRegistry<NhibernateRegistry>());
NhibernateRegistry class:
public class NhibernateRegistry : Registry
{
public NhibernateRegistry()
{
var sessionFactory = NhibernateConfiguration.Configuration.BuildSessionFactory();
For<Configuration>().Singleton().Use(
NhibernateConfiguration.Configuration);
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(
ctx => ctx.GetInstance<ISessionFactory>().GetCurrentSession());
}
}
In Application_BeginRequest i bind opened nhibernate session to asp session(nhibernate session per request) and in EndRequest i unbind them:
protected void Application_BeginRequest(
object sender, EventArgs e)
{
CurrentSessionContext.Bind(ObjectFactory.GetInstance<ISessionFactory>().OpenSession());
}
Q1: How can i realize what SessionFactory should i use according to authenticated user?
is it something like UserData filled with database name (i use simple FormsAuthentication)
For logging i use log4net, namely AdoNetAppender which contains connectionString(in xml, of course).
Q2: How can i manage multiple connection strings for this database appender, so logs would be written to current database? I have no idea how to do that except changing xml all the time and reseting xml configuration, but its really bad solution.
I suppose that it is required to have one session factory per database.
No; you can do just fine with one session factory for both databases.
You just supply an opened IDbConnection as a param to the OpenSession() method of ISessionFactory.
By doing so, you'll lose the possibility for a second level cache, but that might not be a problem.
If you want the second level cache, you need to implement you're own DriverConnectionProvider and supply it via fluent nh's Provider<TYourDriverConnectionProvider>() method.

NHibernate sessions - what's the common way to handle sessions in windows applications?

I've just started using NHibernate, and I have some issues that I'm unsure how to solve correctly.
I started out creating a generic repository containing CUD and a couple of search methods. Each of these methods opens a separate session (and transaction if necessary) during the DB operation(s). The problem when doing this (as far as I can tell) is that I can't take advantage of lazy loading of related collections/objects.
As almost every entity relation has .Not.LazyLoad() in the fluent mapping, it results in the entire database being loaded when I request a list of all entities of a given type.
Correct me if I'm wrong, 'cause I'm still a complete newbie when it comes to NHibernate :)
What is most common to do to avoid this? Have one global static session that remains alive as long as the program runs, or what should I do?
Some of the repository code:
public T GetById(int id)
{
using (var session = NHibernateHelper.OpenSession())
{
return session.Get<T>(id);
}
}
Using the repository to get a Person
var person = m_PersonRepository.GetById(1); // works fine
var contactInfo = person.ContactInfo; // Throws exception with message:
// failed to lazily initialize a collection, no session or session was closed
Your question actually boils down to object caching and reuse. If you load a Foo object from one session, then can you keep hold of it and then at a later point in time lazy load its Bar property?
Each ISession instance is designed to represent a unit of work, and comes with a first level cache that will allow you to retrieve an object multiple times within that unit of work yet only have a single database hit. It is not thread-safe, and should definitely not be used as a static object in a WinForms application.
If you want to use an object when the session under which it was loaded has been disposed, then you need to associate it with a new session using Session.SaveOrUpdate(object) or Session.Update(object).
You can find all of this explained in chapter 10 of the Hibernate documentation.
If this seems inefficient, then look into second-level caching. This is provided at ISessionFactory level - your session factory can be static, and if you enable second-level caching this will effectively build an in-memory cache of much of your data. Second-level caching is only appropriate if there is no underlying service updating your data - if all database updates go via NHibernate, then it is safe.
Edit in light of code posted
Your session usage is at the wrong level - you are using it for a single database get, rather than a unit of work. In this case, your GetById method should take in a session which it uses, and the session instance should be managed at a higher level. Alternatively, your PersonRepository class should manage the session if you prefer, and you should instantiate and dispose an object of this type for each unit of work.
public T GetById(int id)
{
return m_session.Get<T>(id);
}
using (var repository = new PersonRepository())
{
var person = repository.GetById(1);
var contactInfo = person.ContactInfo;
} // make sure the repository Dispose method disposes the session.
The error message you are getting is because there is no longer a session to use to lazy load the collection - you've already disposed it.