Pregunta

Estoy intentando agregar un pojo a una colección en otro pojo. Estoy seguro de que estoy cometiendo un error realmente estúpido en algún lugar a lo largo de las líneas, pero no puedo averiguar cómo resolverlo.

Tengo un Pojo LookupTable que contiene una lista de columnas:

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...
}

En mi configuración de hibernación tengo:

<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>

En mi archivo de configuración de Spring tengo:

<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>

Y finalmente el código donde todo falla dentro de mi clase de administrador (com.foo.LookupTableManager):

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

La variable lookupTableDao aquí se refiere a una clase DAO simple que extiende HibernateDaoSupport.

El error que recibo es:

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 ...

Bien, entiendo el mensaje básico que estoy recibiendo. Pero lo que no entiendo es dónde obtengo la segunda sesión ... ¿Puede alguien ayudarme con esto?

Estoy usando Hibernate 3.2.6.ga, Spring 2.5.5 y Tomcat 6.0

¿Fue útil?

Solución

Resulta que no tuve una transacción en absoluto. Usé casi la misma configuración de transacción en uno de mis otros archivos de configuración.

El punto de corte allí también se llamaba "gestores", por lo que mi asesor aquí hacía referencia al punto de corte en el otro archivo.

El cambio de nombre del corte de puntos solucionó mi problema.

Otros consejos

Supongo que la llamada lookupTableDao.findById está obteniendo su objeto en una sesión, pero la lookupTableDao.saveOrUpdate es diferente: ¿cómo se obtiene la < código> Sesión objeto, a través de Spring?

¿De dónde viene el objeto Column ? ¿Ya está en la base de datos o es nuevo?

El problema fue con la asignación de filtro de sesión abierta en vista. Estaba creando una sesión en getSession Y otro en guardar.

Solo puedes cambiar singleSession como falso predeterminado es verdadero

Aparentemente, usar merge probablemente solucionará el problema

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

Tuve el mismo problema con mi siguiente código: Quería actualizar una cierta tienda de la entidad. Lo estaba recuperando de este método:

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

Luego, estaba actualizando la tienda con el siguiente método:

@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;
        }
    });
} 

Resulta que obtuve el " intento ilegal ... " error porque la primera sesión del método get no se estaba cerrando, y estaba intentando actualizar con la otra sesión la tienda. La solución para mí fue mover la llamada para recuperar el almacén a actualizar en el método de actualización.

@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;
        }
    });
} 

Si solo desea una transacción sobre una parte de su código, puede usar algo como esto:

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

y en la clase:

@Autowired private SessionFactory sessionFactory;

Más tarde, alrededor del código que debería hacer cosas en la misma transacción:

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

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

tx.commit();

Utilizo esto dentro de un bucle en algunos trabajos por lotes de larga ejecución.

Estaba usando el servidor IIS de Windows y solo cambiando el modo de Pipeline Administrado de AppPool de Integrado a Clásico resolvió mi problema.

Gracias

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top