I get a sporadic error that is hard to reproduce. My first guess is that somehow I have a running nhibernate session, however, when I started the nhibernate profiler , I didn't see anything unusual.
- MVC 2.0
- Free version 1.1.0.685
- NHibernate version 2.1.2.4000
Exception: System.ArgumentException: An item with the same key has already been added.
Stack trace: at System.Collections.Generic.Dictionary 2.Insert(TKey key, TValue value, Boolean add) at NHibernate.Util.ThreadSafeDictionary 2.Add (TKey key, TValue value) on NHibernate.SqlTypes.SqlTypeFactory.GetTypeWithLenL ] (Int32 length, TypeWithLenCreateDelegate createDelegate) in NHibernate.Type.EnumStringType..ctor (Type enumClass, Int32 length)
I am using a repository model. Here is my repository class.
public sealed class Repository<T> : IRepository<T> where T : CoreObjectBase { #region IRepository<T> Members private ISession Session { get { return new SessionHelper().GetSession(); } } public IQueryable<T> GetAll() { return (from entity in Session.Linq<T>() select entity); } public T GetById(int id) { return Session.Get<T>(id); } public void Save(params T[] entities) { using (ITransaction tx = Session.BeginTransaction()) { for (int x = 0; x < entities.Count(); x++) { var entity = entities[x]; entity.Validate(); Session.SaveOrUpdate(entities[x]); if (x == entities.Count() - 1 || (x != 0 && x % 20 == 0)) //20 is the batch size { Session.Flush(); Session.Clear(); } } tx.Commit(); } } public void SaveWithDependence<K>(T entity, K dependant) where K : CoreObjectBase { entity.Validate(); dependant.Validate(); using (ITransaction tx = Session.BeginTransaction()) { Session.SaveOrUpdate(entity); Session.SaveOrUpdate(dependant); tx.Commit(); } } public void Save(T entity) { entity.Validate(); using (ITransaction tx = Session.BeginTransaction()) { Session.SaveOrUpdate(entity); tx.Commit(); } } public void Delete(T entity) { using (ITransaction tx = Session.BeginTransaction()) { Session.Delete(entity); tx.Commit(); } } public T GetOne(QueryBase<T> query) { var result = query.SatisfyingElementFrom(Session.Linq<T>()); return result; //return query.SatisfyingElementFrom(Session.Linq<T>()); } public IQueryable<T> GetList(QueryBase<T> query) { return query.SatisfyingElementsFrom(Session.Linq<T>()); } /// <summary> /// remove the sepcific object from level 1 cache so it can be refreshed from the database /// </summary> /// <param name="entity"></param> public void Evict(T entity) { Session.Evict(entity); } #endregion }
And here is my session helper adapted from this .
public sealed class SessionHelper { private static ISessionFactory _sessionFactory; private static ISession _currentSession; public ISession GetSession() { ISessionFactory factory = getSessionFactory(); ISession session = getExistingOrNewSession(factory); return session; } private ISessionFactory getSessionFactory() { if (_sessionFactory == null) { _sessionFactory = BuildSessionFactory(); } return _sessionFactory; } private ISessionFactory BuildSessionFactory() { return Fluently.Configure().Database( FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005 .ConnectionString(c => c .FromConnectionStringWithKey("MyDatabase")) .AdoNetBatchSize(20)) .Mappings(m => m.FluentMappings.AddFromAssemblyOf<SessionHelper>()) .BuildSessionFactory(); } private ISession getExistingOrNewSession(ISessionFactory factory) { if (HttpContext.Current != null) { ISession session = GetExistingWebSession(); if (session == null) { session = openSessionAndAddToContext(factory); } else if (!session.IsOpen) { session = openSessionAndAddToContext(factory); } return session; } if (_currentSession == null) { _currentSession = factory.OpenSession(); } else if (!_currentSession.IsOpen) { _currentSession = factory.OpenSession(); } return _currentSession; } public ISession GetExistingWebSession() { return HttpContext.Current.Items[GetType().FullName] as ISession; } private ISession openSessionAndAddToContext(ISessionFactory factory) { ISession session = factory.OpenSession(); HttpContext.Current.Items.Remove(GetType().FullName); HttpContext.Current.Items.Add(GetType().FullName, session); return session; } }
Any ideas or suggestions to avoid this problem?
Josh
source share