-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Illegal attempt to associate a collection with two open sess
PostPosted: Sun Apr 09, 2006 10:57 pm 
Newbie

Joined: Wed Jul 06, 2005 4:19 pm
Posts: 6
Hi,

I set up two many-to-many association on two properties in my class, and it throws the exception "Illegal attempt to associate a collection with two open sessions".

When I remove one of the mappings, it doesnt throw an error. Im not sure what I need to do to get rid of this error.

I have three files: HotelLocation.hbm.xml, HotelActivity.hbm.xml and HotelCharacteristic.hbm.xml.

Code:
<<< HotelLocation.hbm.xml >>>
...
        <set name="Activities" table="MeetingSpace_HotelLocationActivities" lazy="false" cascade="all">
            <key column="HotelLocationID"/>
            <many-to-many column="HotelActivityID" outer-join="auto" class="CorlukaAssociates.Applications.MeetingSpace.Core.HotelActivity,CorlukaAssociates.Applications.MeetingSpace"   />
        </set>

...

        <set name="Characteristics" table="MeetingSpace_HotelLocationCharacteristics" lazy="false" cascade="save-update">
                <key column="HotelLocationID" />
                <many-to-many column="HotelCharacteristicID" outer-join="auto" class="CorlukaAssociates.Applications.MeetingSpace.Core.HotelCharacteristic,CorlukaAssociates.Applications.MeetingSpace" />
        </set>




Code:
<<< HotelActivity.hbm.xml >>>
...
   <class dynamic-insert="true" dynamic-update="true" lazy="true" name="HotelActivity" table="MeetingSpace_HotelActivities">
      <id name="ID" column="ID" type="Int32" unsaved-value="-1">
         <generator class="native">
            <param name="sequence">HotelActivities_ID_seq</param>
         </generator>
      </id>
      <property name="Name" column="Name" type="string" unique="true" length="64" />
      

   </class>
...



Code:
<<< HotelCharacteristic.hbm.xml >>>
...
   <class name="HotelCharacteristic" table="MeetingSpace_HotelCharacteristics">
      <id name="ID" column="ID" type="Int32" unsaved-value="-1">
         <generator class="native">
            <param name="sequence">HotelCharacteristics_ID_seq</param>
         </generator>
      </id>

      <property name="Name" column="Name"  unique="true" type="string" length="64" />

   </class>
...


Another concern: I am mapping the many-to-many in a set... I tried setting it up with a bag, but the values in the intermediate table were never saved when I committed the saves.. really odd, because the entities on the "other" end of the association where inserted (i.e. the HotelActivity and HotelCharacteristic inserts. Isnt it supposed to work with a bag, or did I miss a setting (I used lazy=true, inverese=true and cascade=all w/ my bag)??

Regards,

Christian


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 09, 2006 11:38 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
It's unlikely that it's your mapping files that are causing this problem. Why have you two sessions open at once? If you do that (e.g. for replicating data to an alternative data source) then you have to fully inflate and detach objects, or perhaps clone them, in order to get them to work across sessions. Uninflated persistent objects are valid only for the session that loaded them.

Re: bags and many-to-manys: they should work. Remember that you can't initially save them via the inverse end, only via the main end. You can update them via the inverse end, but you have to be careful when doing that, becasue the links are not updated (so you can't remove an item from a bag from the inverse end). However, all of this also applies to sets, so if your set is working, your bag should have worked too.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 8:29 am 
Newbie

Joined: Wed Jul 06, 2005 4:19 pm
Posts: 6
Hi,

I dont know why two sessions are open..

I am unsure which pattern to use for data retrieval with NHibernate - I'm using something I adapted from an open-source project..

I am not expecting you to read all of my code (may take too much time), so if you know of a good pattern to use for an NHibernate helper, then Id be happy to do the tinkering to make it work with my code and get back to you if I still have the same problem.

Thank you so much for your help,

Christian

Here's the code, in case you feel inclined:

Code:
<<<< Databroker Class >>>>
public class DataBroker
{
...

      public NHibernateHelper dataHelper;

...
      public int SaveHotelLocation(HotelLocation hotelLocation)
      {
         ITransaction tx = dataHelper.ActiveSession.BeginTransaction();
         
         try
         {
            hotelLocation.ID = (int) dataHelper.ActiveSession.Save(hotelLocation);
            tx.Commit();
            
         }
         catch (Exception ex)
         {
            if(tx!=null) tx.Rollback();
            throw new Exception("Unable to save hotelLocation", ex);
         }
         finally{   dataHelper.ActiveSession.Close(); }

         return hotelLocation.ID;
      }
...
}



Code:
<<<< NHibernateHelper class >>>>
using System;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;

using log4net;
using NHibernate;
using NHibernate.Expression;

namespace NHibernateHelper
{

   public class NHibernateHelper
   {
      private static readonly ILog log = LogManager.GetLogger(typeof(NHibernateHelper));

      private ISessionFactory _factory;
      private ISession _activeSession;

      private static IDictionary getConfigurationSection(string configSectionName)
      {
         object config = ConfigurationSettings.GetConfig(configSectionName);
         Hashtable dictionary = new Hashtable();
         if( config == null )
         {
            return null;
         }

         NameValueCollection properties = config as NameValueCollection;
         if( properties == null )
         {
            return null;
         }

         foreach( string key in properties )
         {
            dictionary[ key ] = properties[ key ];
         }

         return dictionary;
      }

      
      /// <summary>
      /// Get the active NHibernate session.
      /// </summary>
      public ISession ActiveSession
      {
         get { return this._activeSession; }
      }
      
      public NHibernateHelper(string configSectionName, Assembly assembly) : this( NHibernateHelper.getConfigurationSection(configSectionName), assembly )
      {
         
      }
      
      public NHibernateHelper(string configSectionName, Assembly assembly, bool openSession) : this( NHibernateHelper.getConfigurationSection(configSectionName), assembly, openSession)
      {
         
      }

      /// <summary>
      /// Create a repository for core objects.
      /// </summary>
      
      public NHibernateHelper(System.Collections.IDictionary properties, Assembly assembly) : this(properties, assembly, false)
      {
      }

      /// <summary>
      /// Create a repository for core objects.
      /// </summary>
      /// <param name="openSession">Indicate if the CoreRepository should open a session and keep it in memory.</param>
      public NHibernateHelper(System.Collections.IDictionary properties, Assembly assembly, bool openSession)
      {

         this._factory = SessionFactory.GetInstance(properties, assembly).GetNHibernateFactory();
         if (openSession)
         {
            this._activeSession = this._factory.OpenSession();
         }
      }



      
      
      /// <summary>
      /// Open a NHibernate session.
      /// </summary>
      public void OpenSession()
      {
         if (this._activeSession == null || ! this._activeSession.IsOpen)
         {
            this._activeSession = this._factory.OpenSession();
         }
         else
         {
            throw new InvalidOperationException("The repository already has an open session");
         }
      }

      /// <summary>
      /// Flushes the current active NHibernate session.
      /// </summary>
      public void FlushSession()
      {
         if (this._activeSession != null && this._activeSession.IsOpen)
         {
            this._activeSession.Flush();
         }
      }

      /// <summary>
      /// Close the active NHibernate session
      /// </summary>
      public void CloseSession()
      {
         if (this._activeSession != null)
         {
            if (this._activeSession.IsOpen)
            {
               this._activeSession.Close();
            }
            this._activeSession.Dispose();
         }
      }

      #region Generic methods

      /// <summary>
      /// Generic method for retrieving single objects by primary key.
      /// </summary>
      /// <param name="type"></param>
      /// <param name="id"></param>
      /// <returns></returns>
      public object GetObjectById(Type type, int id)
      {
         if (this._activeSession != null)
         {
            return this._activeSession.Load(type, id);
         }
         else
         {
            throw new NullReferenceException("The repository doesn't have an active session");
         }
      }

      /// <summary>
      /// Get all objects of a given type.
      /// </summary>
      /// <param name="type"></param>
      /// <returns></returns>
      public IList GetAll(Type type)
      {
         return GetAll(type, null);
      }

      /// <summary>
      /// Get all objects of a given type and add one or more names of properties to sort on.
      /// </summary>
      /// <param name="type"></param>
      /// <param name="sortProperties"></param>
      /// <remarks>Sorting is Ascending order. Construct a specific query/method when the sort order
      /// should be different.</remarks>
      /// <returns></returns>
      public IList GetAll(Type type, params string[] sortProperties)
      {
         ICriteria crit = this._activeSession.CreateCriteria(type);
         if (sortProperties != null)
         {
            foreach (string sortProperty in sortProperties)
            {
               crit.AddOrder(Order.Asc(sortProperty));
            }
         }
         return crit.List();
      }

      /// <summary>
      /// Generic method to insert an object.
      /// </summary>
      /// <param name="obj"></param>
      public void SaveObject(object obj)
      {
         ITransaction trn = this._activeSession.BeginTransaction();
         try
         {
            // Try to find a UpdateTimestamp property and when found, set it to the current date/time.
            PropertyInfo pi = obj.GetType().GetProperty("UpdateTimestamp");
            if (pi != null)
            {
               pi.SetValue(obj, DateTime.Now, null);
            }
            this._activeSession.Save(obj);
            trn.Commit();
         }
         catch (Exception ex)
         {
            trn.Rollback();
            throw ex;
         }
      }

      /// <summary>
      /// Generic method to update an object.
      /// </summary>
      /// <param name="obj"></param>
      public void UpdateObject(object obj)
      {
         ITransaction trn = this._activeSession.BeginTransaction();
         try
         {
            this._activeSession.Update(obj);
            trn.Commit();
         }
         catch (Exception ex)
         {
            trn.Rollback();
            throw ex;
         }
      }

      /// <summary>
      /// Delete a specific object. Settings in the mapping file determine if this cascades
      /// to related objects.
      /// </summary>
      /// <param name="obj"></param>
      public void DeleteObject(object obj)
      {
         ITransaction trn = this._activeSession.BeginTransaction();
         try
         {
            this._activeSession.Delete(obj);
            trn.Commit();
         }
         catch (Exception ex)
         {
            trn.Rollback();
            throw ex;
         }
      }

      /// <summary>
      /// Mark an object for deletion. Commit the deletion with Session.Flush.
      /// </summary>
      /// <param name="obj"></param>
      public void MarkForDeletion(object obj)
      {
         this._activeSession.Delete(obj);
      }

      #endregion

   }
}





Code:
<<<< SessionFactory class >>>>

using System;
using System.Reflection;

using NHibernate;
using NHibernate.Cfg;

namespace NHibernateHelper
{
   /// <summary>
   /// The SessionFactory provides the NHibernate sessions and provides the possibility to register
   /// additional classes with NHibernate by modules.
   /// </summary>
   public class SessionFactory
   {
      private static SessionFactory __sessionFactory = null;
      
      private static SessionFactory _sessionFactory(System.Collections.IDictionary properties, Assembly assembly)
      {
         if(SessionFactory.__sessionFactory == null) SessionFactory.__sessionFactory = new SessionFactory(properties, assembly);
         return SessionFactory.__sessionFactory;
      }
      
      private Configuration _nhibernateConfiguration;
      private ISessionFactory _nhibernateFactory;
      private bool _classesAdded = false;

      /// <summary>
      /// Default constructor.
      /// </summary>
      protected SessionFactory(System.Collections.IDictionary properties, Assembly assembly)
      {
         RegisterClasses( properties, assembly );
      }

      /// <summary>
      /// Gets the one instance of the SessionFactory. This is done with a singleton so we don't have
      /// to register mappings etc. with every request.
      /// </summary>
      /// <returns></returns>
      public static SessionFactory GetInstance(System.Collections.IDictionary properties, Assembly assembly)
      {
         return _sessionFactory( properties, assembly );
      }

      /// <summary>
      /// GetNHibernateFactory returns the current NHibernate ISessionFactory.
      /// </summary>
      public ISessionFactory GetNHibernateFactory()
      {
         return this._nhibernateFactory;
      }

      /// <summary>
      /// Get a new NHibernate session.
      /// </summary>
      /// <returns></returns>
      public ISession GetSession()
      {
         return this._nhibernateFactory.OpenSession();
      }

      /// <summary>
      /// Add a class to the NHibernate mappings.
      /// If the class already is mapped, nothing will happen.
      /// </summary>
      /// <param name="type"></param>
      public void RegisterPersistentClass(Type type)
      {
         if (this._nhibernateConfiguration.GetClassMapping(type) == null)
         {
            // Class isn't mapped yet, so do it now.
            this._nhibernateConfiguration.AddClass(type);
            this._classesAdded = true;
         }         
      }

      /// <summary>
      /// Rebuild the NHibernate ISessionFactory. Use it after registering new classes.
      /// </summary>
      public bool Rebuild()
      {
         // Rebuild NHibernate SessionFactory to activate the new mapping.
         if (this._classesAdded)
         {
            this._nhibernateFactory = this._nhibernateConfiguration.BuildSessionFactory();
            this._classesAdded = false;
            return true;
         }
         else
         {
            return false;
         }
      }

      private void RegisterClasses(System.Collections.IDictionary properties, Assembly assembly )
      {
         Configuration config = new Configuration();
         config.AddProperties(properties);
         this._nhibernateConfiguration = config.AddAssembly( assembly );
         this._nhibernateFactory = this._nhibernateConfiguration.BuildSessionFactory();
      }
   }
}



Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 12:49 pm 
Newbie

Joined: Wed Jul 06, 2005 4:19 pm
Posts: 6
Hi again..

Just to give an update: I still cannot resolve the problem, and I rewrote my Data class to use a HibernateUtil - exactly as suggested on page 297 of the "Hibernate in Action" book..

I am still getting the error.. Next, I guess I will have to step through the NHibernate source code to find out what is wrong.

Is there a log so I can see if a session is opened?

regards,

Christian


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 1:32 pm 
Newbie

Joined: Wed Jul 06, 2005 4:19 pm
Posts: 6
FYI: Everything worked out.

The problem may have been caused by me not closing my sessions after retrieving objects.. at least this is what it appeared to be the problem.

// christian


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.