2008-10-21 12 views
10

Ich versuche, einer Sammlung in einem anderen Pojo ein Pojo hinzuzufügen. Ich bin mir sicher, dass ich irgendwo entlang der Linien einen wirklich dummen Fehler mache, aber ich kann nicht herausfinden, wie ich es lösen soll.Illegaler Versuch, eine Sammlung mit zwei offenen Sitzungen zu verknüpfen

Ich habe eine pojo LookupTable die eine Liste der Spalte enthält:

public class LookupTable { 
    private long id; 
    // More properties go here... 
    private List<Column> columns; 

    public void addColumn(Column column) { 
    this.columns.add(column); 
    } 

    // More methods go here... 
} 

In meinem Hibernate Konfiguration Ich habe:

<class name="LookupTable" table="ARR_LOOKUP_TABLE"> 
    <id name="id" column="ID"> 
    <generator class="native"/> 
    </id> 
    <!-- Some properties here --> 
    <bag name="columns" cascade="all,delete-orphan" access="field"> 
    <key column="LOOKUP_TABLE" not-null="true"/> 
    <one-to-many class="Column"/> 
    </bag> 
</class> 

<class name="Column" table="ARR_LOOKUP_COLUMN"> 
    <id name="id" column="ID"> 
    <generator class="native"/> 
    </id> 
    <!-- Some properties here --> 
</class> 

In meinem Frühling Configakte ich habe:

<tx:advice id="txAdvice" transaction-manager="txManager"> 
    <tx:attributes> 
    <tx:method name="*" propagation="REQUIRED"/> 
    </tx:attributes> 
</tx:advice> 
<aop:config> 
    <aop:pointcut id="managers" expression="execution(public * com.foo.*Manager.*(..))"/> 
    <aop:advisor advice-ref="txAdvice" pointcut-ref="managers"/> 
</aop:config> 

Und schließlich der Code, wo alles in meiner Manager-Klasse (com.foo.LookupTableManager) fehlschlägt:

public void addColumnToTable(Column column, long tableId) { 
    LookupTable lookupTable = this.lookupTableDao.findById(tableId); 
    lookupTable.addColumn(column); 
    this.lookupTableDao.saveOrUpdate(lookupTable); 
} 

Die Variable lookupTableDao bezieht sich hier auf eine einfache DAO-Klasse, die HibernateDaoSupport erweitert.

Der Fehler, den ich bekommen ist:

org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions 
    at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410) 
    at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:43) 
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101) 
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61) 
    at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55) 
    at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:89) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70) 
    at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495) 
    at com.foo.AbstractDao.saveOrUpdate(AbstractDao.java:29) 
    at com.foo.LookupTableManager.addColumnToTable(LookupTableManager.java:338) 
... etc ... 

OK, ich verstehe die grundlegende Botschaft, die ich bin immer. Aber was ich nicht verstehe ist, wo ich die zweite Sitzung bekomme ... Kann mir jemand dabei helfen?

ich Hibernate 3.2.6.ga bin mit, Frühling 2.5.5 und Tomcat 6.0

Antwort

4

Oh Mist, die Lösung war ein wenig zu einfach. Es stellte sich heraus, dass ich überhaupt keine Transaktion hatte. Ich verwendete fast die gleiche Transaktionskonfiguration in einer meiner anderen Konfigurationsdateien. Der Pointcut da drüben wurde auch "Manager" genannt, also referenzierte mein Berater hier den Pointcut in der anderen Datei. Das Umbenennen des Pointcuts hat mein Problem gelöst.

2

Meine Vermutung ist, dass der lookupTableDao.findById Anruf Ihr Objekt in einer Sitzung wird immer, aber die lookupTableDao.saveOrUpdate ist ein anderer - wie erhalten Sie das Session Objekt über Frühling?

Woher kommt das Column Objekt - ist das schon auf der DB oder neu?

+0

[Bearbeiten, bewegt Antwort auf einen Kommentar]: Ich bin die Sitzung über die getSession() -Methode von org.springframework.orm.hibernate.support.HibernateDaoSupport bekommen. Das sollte die Sitzung von der aktuellen Transaktion zurückgeben ... Das Column-Objekt wird neu erstellt. –

1

Das Problem war mit dem Filter Filter Mapping der Sitzung in der Ansicht. Es wurde eine Sitzung auf getSession Und andere beim Speichern erstellt.

können Sie nur singleSession als falsch Standard ändern ihre wahre

1

Anscheinend merge verwendet, wird wahrscheinlich das Problem

myInstance = (myInstanceClass) Session.merge(myInstance); 
0

beheben Wenn Sie nur eine Transaktion über einen Teil des Codes möchten, können Sie etwas verwenden wie folgt aus:

import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.Transaction; 

und in der Klasse:

@Autowired private SessionFactory sessionFactory; 

Später, um den Code, der die Dinge in derselben Transaktion tun soll:

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 

Stuff stuff = getStuff(); 
manipulate(stuff); 
send(stuff); 
save(stuff); 

tx.commit(); 

Ich benutze diese in einer Schleife in einigen lang laufenden Batch-Jobs.

1

Ich hatte das gleiche Problem mit meinem folgenden Code: Ich wollte eine bestimmte Entität Store aktualisieren. Ich war es von dieser Methode Abrufen:

@Override 
public Store getStoreByStoreId(final long storeId) { 
    getHibernateTemplate().execute(new HibernateCallback<Store>() { 
     @Override 
     public StoredoInHibernate(Session session) throws HibernateException, SQLException { 
      return (Store) session.createCriteria(Store.class) 
        .add(Restrictions.eq(Store.PROP_ID, storeId)) 
        .uniqueResult(); 
     } 
    }); 
} 

Dann wurde ich in dem folgende Verfahren Shop Aktualisierung:

@Override 
public void updateStoreByStoreId(final long storeId) { 
    getHibernateTemplate().execute(new HibernateCallback<Void>() { 
     @Override 
     public Void doInHibernate(Session session) throws HibernateException, SQLException { 
      Store toBeUpdated = getStoreByStoreId(storeId); 

      if (toBeUpdated != null){ 
       // ..change values for certain fields 
       session.update(toBeUpdated); 
      } 
      return null; 
     } 
    }); 
} 

Es stellt sich heraus, dass ich das bekam „Illegal Versuch ...“ Fehler, weil die Die erste Sitzung von der Methode get wurde nicht geschlossen, und ich versuchte, mit der anderen Sitzung den Speicher zu aktualisieren. Die Lösung für mich war, den Aufruf zum Abrufen des Speichers, der aktualisiert werden soll, in der Aktualisierungsmethode zu verschieben.

@Override 
public void updateStoreByStoreId(final long storeId) { 
    getHibernateTemplate().execute(new HibernateCallback<Void>() { 
     @Override 
     public Void doInHibernate(Session session) throws HibernateException, SQLException { 
      Store toBeUpdated = (Store) session.createCriteria(Store.class) 
        .add(Restrictions.eq(Store.PROP_ID, storeId)) 
        .uniqueResult(); 

      if (toBeUpdated != null){ 
       // ..change values for certain fields 
       session.update(toBeUpdated); 
      } 
      return null; 
     } 
    }); 
} 
0

Ich habe Windows Server IIS verwendet und nur den AppPool Managed Pipeline-Modus von Integrated zu Classic geändert löste mein Problem.

Dank