NHibernate: System.Argument Exception: an item with the same key has already been added

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?

+7
source share
3 answers

The problem is that SessionHelper not thread safe. It can potentially create several session factories (this is a poor implementation of Singleton), which in turn can cause the error you see.

I recommend using SharpArchitecture instead .

+2
source

I ran into the same problem: "An item with the same key has already been added" when building the nhibernate configuration.

What happened to me was that in two threads different configurations were created programmatically, designed to connect to different databases at the same time.

I added a lock for the entire configuration configuration, and the problem disappeared.

Therefore, I assume that the configuration object depends on some internal global state, i.e. assumes that the configuration itself is singleton (as I suppose, it would be if it were completely file-driven, as opposed to software-built).

+1
source

I understand this is an old question, but I had a similar error just a few days ago using NHibernate 3.0.

For readers who might stumble upon this problem: this is the result of a known thread safety issue in older versions of NHibernate. This has been fixed in version 3.2, but older versions will not have a fix and may cause this problem. This error entry describes the problem: https://nhibernate.jira.com/browse/NH-3271

+1
source

All Articles