MVC 3/EF/SQL Handling Connections, Disposal and Timeouts - sql

Currently, this is how I am handling data within my MVC 3 application. Being pretty new to both MVC 3 and the Entity Framework I am not quite sure this is the best approach to handling data within the application. In fact, the call to check UserExists below sometimes gives a SQLConnectionTimeout issue which seems to be completely random. I've tried tracing the problem through SQL profiler and it appears that the timeout occurs right after the connection is being made from EF -> SQL.
I thought I had this solved in another question here on SO but it popped back up, so I wanted to get everyone's opinion on whether or not below is the best way to attempt data handling in my application or is there a better way that may solve the timeout issue.
Here is a link to the other article if it helps: MVC 3/EF/SQL Server strange connection timeout issue
So to summarize my question(s):
Is the code below acceptable?
Should it work fine?
Is there a better way?
Will unnecessary connections to SQL remain open from EF? (SQL Profiler makes it look like it stays open a while even after the using statement has exited)
Any idea on the timeout issue I posted in my other article?
Note: The repository implements IDisposable and has the dispose method listed below. It creates a new instance of the entity context in the repository constructor.
Controller (LogOn using Custom Membership Provider):
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
User newUser = new User();
using (AccountRepository repo = new AccountRepository())
{
newUser = repo.GetUser(model.UserName);
...
}
}
Membership Provider ValidateUser:
public override bool ValidateUser(string username, string password)
{
using (AccountRepository repo = new AccountRepository())
{
try
{
if (string.IsNullOrEmpty(password.Trim()) || string.IsNullOrEmpty(username.Trim()))
return false;
string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(password.Trim(), "md5");
bool exists = false;
exists = repo.UserExists(username, hash);
return exists;
}catch{
return false;
}
}
}
Account Repository Methods for GetUser & UserExists:
Get User:
public User GetUser(string userName)
{
try
{
return entities.Users.SingleOrDefault(user => user.UserName == userName);
}
catch (Exception Ex)
{
throw new Exception("An error occurred: " + Ex.Message);
}
}
User Exists:
public bool UserExists(string userName, string userPassword)
{
if (userName == "" || userPassword == "")
throw new ArgumentException(InvalidUsernamePassword);
try
{
bool exists = (entities.Users.SingleOrDefault(u => u.UserName == userName && u.Password == userPassword) != null);
return exists;
}
catch (Exception Ex)
{
throw new Exception("An error occurred: " + Ex.Message);
}
}
Repository Snippets (Constructor, Dispose etc):
public class AccountRepository : IDisposable
{
private DbContext entities;
public AccountRepository()
{
entities = new DbContext();
}
...
public void Dispose()
{
entities.Dispose();
}
}
Thanks everyone - I realize that this question crit's you for over 9000 with a giant wall of text!

We generally follow the pattern of controlling the instantiation and disposal of the context using an IActionFilter and providing a mechanism to inject that into dependent classes (using Ninject).
If you're not using dependency injection / IoC you can get away with a base controller a little like the following:
using System;
using System.Diagnostics;
using System.Linq;
using System.Transactions;
using System.Web.Mvc;
public class ControllerBase : Controller
{
private ContextState contextState;
protected EntityContext Context
{
get { return this.contextState.Context; }
}
protected TransactionScope TransactionScope
{
get { return this.contextState.TransactionScope; }
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
IsolationLevel isolationLevel = filterContext.ActionDescriptor
.GetCustomAttributes(typeof(UnitOfWorkAttribute), false)
.Cast<UnitOfWorkAttribute>()
.Select(a => a.IsolationLevel)
.DefaultIfEmpty(IsolationLevel.ReadCommitted)
.First();
Trace.TraceInformation("Creating database context & transaction scope with isolation {0}.", isolationLevel);
this.contextState = new ContextState
{
TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { IsolationLevel = isolationLevel }),
Context = new EntityContext()
};
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
try
{
if (filterContext.Exception == null)
{
Trace.TraceInformation("Commiting transaction scope.");
this.contextState.TransactionScope.Complete();
}
else
{
Trace.TraceInformation("Rolling back transaction scope.");
}
}
finally
{
try
{
Trace.TraceInformation("Disposing database context.");
this.contextState.Context.Dispose();
}
catch (Exception e)
{
Trace.TraceError("Failed to dispose database context. {0}", e);
}
try
{
Trace.TraceInformation("Disposing transaction scope.");
this.contextState.TransactionScope.Dispose();
}
catch (Exception e)
{
Trace.TraceError("Failed to dispose transaction scope. {0}", e);
}
this.contextState = null;
}
}
private class ContextState
{
public EntityContext Context { get; set; }
public TransactionScope TransactionScope { get; set; }
}
}
/// <summary>
/// Marks an MVC action as requiring a particular <see cref="IsolationLevel" /> when a transaction is
/// created for it.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class UnitOfWorkAttribute : Attribute
{
private readonly IsolationLevel isolationLevel;
public UnitOfWorkAttribute(IsolationLevel isolationLevel)
{
this.isolationLevel = isolationLevel;
}
/// <summary>
/// Gets an <see cref="IsolationLevel" /> value indicating the isolation level
/// a transaction should use.
/// </summary>
public IsolationLevel IsolationLevel
{
get
{
return this.isolationLevel;
}
}
}
Here we create an instance of your context and a transaction scope just before an action executes and then we cleanup once the action has finished up.
In your derived controller you can then do the following...
public class HomeController : ControllerBase
{
public ActionResult Index()
{
using (AccountRepository accountRepository = new AccountRepository(this.Context))
{
// do stuff
}
return View();
}
}
Passing the context into your repository is a little messy and can be tidied up using something like Ninject to inject the dependency rather than you providing it. http://stevescodingblog.co.uk/dependency-injection-beginners-guide/ provides a pretty reasonable starting point if you're interested.
You can also mark up an action with the UnitOfWorkAttribute to control creation of the transaction used by the context. It's recommended not to use implicit transaction when doing database work (http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions) so we always create a transaction scope when executing the action. This has little overhead because, unless the connection is opened, the transaction scope doesn't do much.
Edit: Just to answer another of your questions...
Will unnecessary connections to SQL remain open from EF? (SQL Profiler makes it look like it stays open a while even after the using statement has exited)
Most likely reason here is connection pooling. ADO.NET will maintain open connections for a period of time which makes subsequent calls more efficient because you don't have the latency of opening the connection.
Cheers,
Dean

Related

Closing connection when using Dapper

Is it necessary to close connection once query is executed explicitly calling Close method or putting the connection within Using statement? Would leaving connection open lead to connection reuse and improve SQL performance for future queries?
I am assuming that you are using latest version of Dapper.
With Dapper, there are two ways to manage connection:
Fully manage yourself:
Here, you are fully responsible for opening and closing connection. This is just like how you treat connection while working with ADO.NET.
Allow Dapper to manage it:
Dapper automatically opens the connection (if it was not opened) and closes it (if it was opened by Dapper) for you. This is similar to DataAdapter.Fill() method. I personally do not recommend this way. This may not be applicable every time. Following is what Marc Gravell says in one of the comment for this answer: https://stackoverflow.com/a/12629170/5779732
well, technically open/closed is different to disposed. If you are only going to be opening/closing around the individual calls, you might as well let dapper do it. If you are opening/closing at a wider granularity (per request, for example), it would be better for your code to do it and pass an open connection to dapper.
Below is the quote from here:
Dapper will close the connection if it needed to open it. So if you're just doing 1 quick query - let Dapper handle it. If you're doing many, you should open (once) and close at the end, with all the queries in the middle...just from an efficiency standpoint.
Ofcourse, you can call multiple queries on single connection. But, connection should be closed (by calling Close(), Dispose() method or by enclosing it in using block) to avoid resource leak. Closing connection returns it to connection pool. Involvement of connection pool improves the performance over new connection cost.
In addition to just handling connection, I suggest you implement UnitOfWork to manage transactions as well. Refer this excellent sample on GitHub.
Following source code may help you. Note that this is written for my needs; so it may not work for you as is.
public sealed class DalSession : IDisposable
{
public DalSession()
{
_connection = new OleDbConnection(DalCommon.ConnectionString);
_connection.Open();
_unitOfWork = new UnitOfWork(_connection);
}
IDbConnection _connection = null;
UnitOfWork _unitOfWork = null;
public UnitOfWork UnitOfWork
{
get { return _unitOfWork; }
}
public void Dispose()
{
_unitOfWork.Dispose();
_connection.Dispose();
}
}
public sealed class UnitOfWork : IUnitOfWork
{
internal UnitOfWork(IDbConnection connection)
{
_id = Guid.NewGuid();
_connection = connection;
}
IDbConnection _connection = null;
IDbTransaction _transaction = null;
Guid _id = Guid.Empty;
IDbConnection IUnitOfWork.Connection
{
get { return _connection; }
}
IDbTransaction IUnitOfWork.Transaction
{
get { return _transaction; }
}
Guid IUnitOfWork.Id
{
get { return _id; }
}
public void Begin()
{
_transaction = _connection.BeginTransaction();
}
public void Commit()
{
_transaction.Commit();
Dispose();
}
public void Rollback()
{
_transaction.Rollback();
Dispose();
}
public void Dispose()
{
if(_transaction != null)
_transaction.Dispose();
_transaction = null;
}
}
interface IUnitOfWork : IDisposable
{
Guid Id { get; }
IDbConnection Connection { get; }
IDbTransaction Transaction { get; }
void Begin();
void Commit();
void Rollback();
}
Now, your repositories should accept this UnitOfWork in some way. I choose Dependency Injection with Constructor.
public sealed class MyRepository
{
public MyRepository(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
IUnitOfWork unitOfWork = null;
//You also need to handle other parameters like 'sql', 'param' ect. This is out of scope of this answer.
public MyPoco Get()
{
return unitOfWork.Connection.Query(sql, param, unitOfWork.Transaction, .......);
}
public void Insert(MyPoco poco)
{
return unitOfWork.Connection.Execute(sql, param, unitOfWork.Transaction, .........);
}
}
And then you call it like this:
With transaction:
using(DalSession dalSession = new DalSession())
{
UnitOfWork unitOfWork = dalSession.UnitOfWork;
unitOfWork.Begin();
try
{
//Your database code here
MyRepository myRepository = new MyRepository(unitOfWork);
myRepository.Insert(myPoco);
//You may create other repositories in similar way in same scope of UoW.
unitOfWork.Commit();
}
catch
{
unitOfWork.Rollback();
throw;
}
}
Without Transaction:
using(DalSession dalSession = new DalSession())
{
//Your database code here
MyRepository myRepository = new MyRepository(dalSession.UnitOfWork);//UoW have no effect here as Begin() is not called.
myRepository.Insert(myPoco);
}
This way, instead of directly exposing connection in your calling code, you control it at one location.
More details about Repository in above code could be found here.
Please note that UnitOfWork is more than just a transaction. This code handles only transaction though. You may extend this code to cover additional roles.

Repository Pattern with Fluent Nhibernate

Hello everyone I've successfully implemented the repository pattern with fluentNHibernate but i have one concern abount the ExposeConfiguration when I removed it all the methods works fine but when i adds it ,it resets the tables in the database. so i need you to take a look and give me any notes about the implementation so here is my unit of work class
public class UnitOfWork
{
public static ISession NhibernateHelper()
{
ISessionFactory _sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(#"Data Source=WAAIL-PC\COMPUTERENGINEER;Initial Catalog=TSQL2012;User ID=sa;Password=12345678Ce").ShowSql())
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<UsersMap>())
//.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(false, true)) //when i removed this line it doesn't
//remove the elements from the db
.BuildSessionFactory();
return _sessionFactory.OpenSession();
}}
and here is my repository pattern :
public class Repository<T> :IRepository<T> where T :BaseEntity
{
public Repository(/*IUnitOfWork unitOfWork*/)
{
//_unitOfWork = (UnitOfWork)unitOfWork;
}
public List<T> GetAll()
{
using (ISession Session = UnitOfWork.NhibernateHelper())
{
return Session.Query<T>().ToList();
}
}
public T GetById(int id)
{
using (ISession Session = UnitOfWork.NhibernateHelper())
{
return Session.Get<T>(id);
}
}
public T Insert(T entity)
{
try
{
using (ISession Session = UnitOfWork.NhibernateHelper())
{
using (ITransaction Transaction = Session.BeginTransaction())
{
Session.Save(entity);
Transaction.Commit();
}
}
return entity;
}
catch (Exception)
{
throw;
}
}
public void Update(T entity)
{
using (ISession Session = UnitOfWork.NhibernateHelper())
{
using (ITransaction Transaction = Session.BeginTransaction())
{
Session.Update(entity);
Transaction.Commit();
}
}
}
public void Delete(int id)
{
using (ISession Session = UnitOfWork.NhibernateHelper())
{
using (ITransaction Transaction = Session.BeginTransaction())
{
Session.Delete(Session.Load<T>(id));
Transaction.Commit();
}
}
}
}
here is my usersService
public class UsersService : IUsersService
{
private readonly IRepository<Users> _Repository;
#region Constructor
public UsersService(IRepository<Users> Repository)
{
_Repository = Repository;
}
#endregion
#region Service Implementation
public List<Users> GetListAll()
{
return _Repository.GetAll().ToList();
}
public Users GetById(int Id)
{
return _Repository.GetById(Id);
}
public Users Insert(Users user)
{
return _Repository.Insert(user);
}
public void Update(Users user)
{
_Repository.Update(user);
}
public void Delete(int Id)
{
_Repository.Delete(Id);
}
//public int execute()
//{
// return _Repository.execute();
//}
}
so what i need to know is why the Expose_configuration method causes the tables to reset... and secondly ,Am i moving in the right way in this implementation or not.
if you guys have any update of improvements please tell me ..
best regards.
The evil lies in details
You wrote:
... ExposeConfiguration when I removed it all the methods works fine but when i add it, it resets the tables in the database.
And that's pretty much normal way of operations, since if we look up NHiberate's SchemaExport classes Create method signature, it reads:
public void Create(Action<string> scriptAction, bool execute)
It's documentation states that Create():
Run the schema creation script
And about it parameters:
scriptAction - an action that will be called for each line of the generated ddl.
execute - if the ddl should be executed against the Database.
And you call it as:
.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(false, true))
Your problem lies in that you pass true to the execute parameter, which will -as stated in documentation- execute the schema creation script, which might include drop and rerecration of existing database objects.
Why create demons?
About your second idea, I really see no benefit of adding another layer of indirection to your code, and that's where you summon unneeded demons.
The NHibernate ORM itself is an abstraction itself, why add one more generic one around it? Your Repository<T> just simply calls the already implemented generic NHibernate methods... sort of acting as Proxy to hide NHibernate, if that's intentional please pardon me, but it looks like it's not.
On a final note: your UsersService class first violates the Single responsibility principle and makes your life harder by maintaining and testing it. Second, this class is also not much more than a proxy to call the repository to return values from.
Let me illustrate the problem:
Client calls UsersService.GetById(Id)
Service calls _Repository.GetById(Id)
Your generic abstraction Repository calls NHibernates Session.Get<T>(id)
Do you see the problem?
How easier it would be to say use a pattern that might help you in this case, that is the Command Query Separation.
Where your commands are responsible for writes, and queries about reads and both suits your use-cases.
You can read about my answers earlier about queries and commands.

Custom action filter unity dependency injection web api 2

I followed this article and got everything working except dependency inject (partially). In my project I am using unity and I am trying to create a custom Transaction attribute the purpose of which is to start a NHibernate transaction before the execution of an action and commit/rollback the transaction after the method execution.
This is the definition of my attribute:-
public class TransactionAttribute : Attribute
{
}
Following is the definition of my TransactionFilter
public class TransactionFilter : IActionFilter
{
private readonly IUnitOfWork _unitOfWork;
public TransactionFilter(IUnitOfWork uow) {
_unitOfWork = uow;
}
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) {
var transAttribute = actionContext.ActionDescriptor.GetCustomAttributes<TransactionAttribute>().SingleOrDefault();
if (transAttribute == null) {
return continuation();
}
var transaction = uow.BeginTransaction();
return continuation().ContinueWith(t =>
{
try{
transaction.Commit();
return t.Result;
}
catch(Exception e)
{
transaction.Rollback();
return new ExceptionResult(ex, actionContext.ControllerContext.Controller as ApiController).ExecuteAsync(cancellationToken).Result;
}
}
}
}
And I have created a custom filter provider which uses unity to construct this filter.
public class UnityActionFilterProvider
: ActionDescriptorFilterProvider,
IFilterProvider
{
private readonly IUnityContainer container;
public UnityActionFilterProvider(IUnityContainer container)
{
this.container = container;
}
public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
foreach (IActionFilter actionFilter in container.ResolveAll<IActionFilter>())
{
// TODO: Determine correct FilterScope
yield return new FilterInfo(actionFilter, FilterScope.Global);
}
}
}
I register the UnityActionFilterProvider in UnityWebApiActivator (I am using Unity.AspNet.WebApi package) as follows
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityDependencyResolver(container);
var config = GlobalConfiguration.Configuration;
config.DependencyResolver = resolver;
var providers = config.Services.GetFilterProviders();
var defaultProvider = providers.Single(i => i is ActionDescriptorFilterProvider);
config.Services.Remove(typeof(IFilterProvider), defaultProvider);
config.Services.Add(typeof(IFilterProvider), new UnityActionFilterProvider(container));
}
The problem is everything works ok for the first request for any action but subsequent requests for the same action doesn't recreate the TransactionFilter which means it doesn't call the constructor to assign a new UOW. I don't think I can disable the action filter caching.
The only option I have got now is to use the service locator pattern and get UOW instance using container inside ExecuteActionFilterAsync which in my opinion kills the purpose of this and I am better off implementing custom ActionFilterAttribute.
Any suggestions ?
As far as I've been able to tell during the years, what happens in web application startup code essentially has Singleton lifetime. That code only runs once.
This means that there's only a single instance of each of your filters. This is good for performance, but doesn't fit your scenario.
The easiest solution to that problem, although a bit of a leaky abstraction, is to inject an Abstract Factory instead of the dependency itself:
public class TransactionFilter : IActionFilter
{
private readonly IFactory<IUnitOfWork> _unitOfWorkFactory;
public TransactionFilter(IFactory<IUnitOfWork> uowFactory) {
_unitOfWorkFactory = uowFactory;
}
// etc...
Then use the factory in the ExecuteActionFilterAsync method:
var transaction = _unitOfWorkFactory.Create().BeginTransaction();
A more elegant solution, in my opinion, would be to use a Decoraptor that Adapts the TransactionFilter, but the above answer is probably easier to understand.

NHibernate, transactions and TransactionScope

I'm trying to find the best solution to handle transaction in a web application that uses NHibernate.
We use a IHttpModule and at HttpApplication.BeginRequest we open a new session and we bind it to the HttpContext with ManagedWebSessionContext.Bind(context, session); We close and unbind the session on HttpApplication.EndRequest.
In our Repository base class, we always wrapped a transaction around our SaveOrUpdate, Delete, Get methods like, according to best practice:
public virtual void Save(T entity)
{
var session = DependencyManager.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
transaction.Commit();
}
}
But then this doesn't work, if you need to put a transaction somewhere in e.g. a Application service to include several repository calls to Save, Delete, etc..
So what we tried is to use TransactionScope (I didn't want to write my own transactionmanager). To test that this worked, I use an outer TransactionScope that doesn't call .Complete() to force a rollback:
Repository Save():
public virtual void Save(T entity)
{
using (TransactionScope scope = new TransactionScope())
{
var session = DependencyManager.Resolve<ISession>();
session.SaveOrUpdate(entity);
scope.Complete();
}
}
The block that uses the repository:
TestEntity testEntity = new TestEntity { Text = "Test1" };
ITestRepository testRepository = DependencyManager.Resolve<ITestRepository>();
testRepository.Save(testEntity);
using (var scope = new TransactionScope())
{
TestEntity entityToChange = testRepository.GetById(testEntity.Id);
entityToChange.Text = "TestChanged";
testRepository.Save(entityToChange);
}
TestEntity entityChanged = testRepository.GetById(testEntity.Id);
Assert.That(entityChanged.Text, Is.EqualTo("Test1"));
This doesn't work. But to me if NHibernate supports TransactionScope it would! What happens is that there is no ROLLBACK at all in the database but when the testRepository.GetById(testEntity.Id); statement is executed a UPDATE with SET Text = "TestCahgned" is fired instead (It should have been fired between BEGIN TRAN and ROLLBACK TRAN). NHibernate reads the value from the level1 cache and fires a UPDATE to the database. Not expected behaviour!? From what I understand whenever a rollback is done in the scope of NHibernate you also need to close and unbind the current session.
My question is: Does anyone know of a good way to do this using TransactionScope and ManagedWebSessionContext?
I took a very similar approach. In the HttpModule I ask the sessionfactory for a new session + bind it when a new request comes in. But I also begin the transaction here. Then when the request is ending I simply unbind it and attempt to commit the transaction.
Also my base repository doesn't take a session in any way - it instead will ask for the current session and then perform some work with the session. Also I don't wrap anything inside this base class with a transaction. Instead the entire http request is a single unit of work.
This might not be appropriate for the project you are working on, but I prefer this approach because each request will fail or succeed as a single atomic unit. I have a full blog post here with source code if you are interested in the actual implementation.
The below is a sample of what this base repository looks like:
public abstract class NHibernateRepository<T> where T : class
{
protected readonly ISessionBuilder mSessionBuilder;
public NHibernateRepository()
{
mSessionBuilder = SessionBuilderFactory.CurrentBuilder;
}
public T Retrieve(int id)
{
ISession session = GetSession();
return session.Get<T>(id);
}
public void Save(T entity)
{
ISession session = GetSession();
session.SaveOrUpdate(entity);
}
public void Delete(T entity)
{
ISession session = GetSession();
session.Delete(entity);
}
public IQueryable<T> RetrieveAll()
{
ISession session = GetSession();
var query = from Item in session.Linq<T>() select Item;
return query;
}
protected virtual ISession GetSession()
{
return mSessionBuilder.CurrentSession;
}
}
Thanks for the answer!
Yes, it's a simple and straightforward way to solve it. But my problem is that I want to make sure that there is a transaction surrounding a repository operation, even if the application service, repository etc is not called by a web request (other types of clients), therefore I wanted to have a transaction surrounding the lowest level (e.g. session.Save) and then use TransactionScope to create a longer transaction if needed. But your solution is simple and I like that, mabye I'll use that and then make sure that other clients use transactions aswell.
The transaction lifecycle should be:
using (TransactionScope tx = new TransactionScope())
{
using (ISession session1 = ...)
using (ITransaction tx1 = session.BeginTransaction())
{
...do work with session
tx1.Commit();
}
using (ISession session2 = ...)
using (ITransaction tx2 = session.BeginTransaction())
{
...do work with session
tx2.Commit();
}
tx.Complete();
}
You can actually check to see if a transaction is active using: Session.Transaction.IsActive. If one isn't active, you can create one. You could also create a Transact method that does most of this for you automatically. Here's an excerpt that's mostly from NHibernate 3.0 Cookbook:
// based on NHibernate 3.0 Cookbook, Data Access Layer, pg. 192
public class GenericDataAccessObject<TId> : IGenericDataAccessObject<TId>
{
// if you don't want to new up your DAO per Unit-of-work you can
// resolve the session at the time it's accessed.
private readonly ISession session;
protected GenericDataAccessObject(ISession session)
{
this.session = session;
}
protected ISession Session { get { return session; } }
public virtual T Get<T>(TId id)
{
return Transact(() => Session.Get<T>(id));
}
protected virtual void Save<T>(T entity)
{
Transact(() => Session.Save(entity));
}
/// <summary>
/// Perform func within a transaction block, creating a new active transaction
/// when necessary. No error handling is performed as this function doesn't have
/// sufficient information to provide a useful error message.
/// </summary>
/// <typeparam name="TResult">The return type</typeparam>
/// <param name="func">The function wrapping the db operations</param>
/// <returns>The results returned by <c>func</c></returns>
protected TResult Transact<TResult>(Func<TResult> func)
{
// the null Transaction shouldn't happen in a well-behaving Session
// implementation
if (Session.Transaction == null || !Session.Transaction.IsActive)
{
TResult result;
// transaction rollback happens during dispose when necessary
using (var tx = Session.BeginTransaction())
{
result = func.Invoke();
tx.Commit();
}
return result;
// We purposefully don't catch any exceptions as if we were to catch
// the error at this point we wouldn't have enough information to describe
// to the user why it happened -- we could only describe what happened.
}
return func.Invoke();
}
protected void Transact(Action action)
{
Transact<bool>(() =>
{
action.Invoke();
return false;
}
);
}
}

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();
}
.
.
.