Domanda

Sto cercando di aggiungere un pojo a una raccolta in un altro pojo. Sono sicuro che sto facendo un errore davvero stupido da qualche parte lungo la linea ma non riesco a capire come risolverlo.

Ho un pojo LookupTable che contiene un elenco di colonne:

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

Nella mia configurazione di ibernazione ho:

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

Nel mio file di configurazione Spring ho:

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

E infine il codice in cui tutto fallisce all'interno della mia classe manager (com.foo.LookupTableManager):

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

La variabile lookupTableDao qui si riferisce a una semplice classe DAO che estende HibernateDaoSupport.

L'errore che ottengo è:

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, capisco il messaggio di base che sto ricevendo. Ma quello che non capisco è dove ottengo la seconda sessione ... Qualcuno può aiutarmi con questo?

Sto usando Hibernate 3.2.6.ga, Spring 2.5.5 e Tomcat 6.0

È stato utile?

Soluzione

Si è scoperto che non avevo alcuna transazione. Ho usato quasi la stessa configurazione di transazione in uno dei miei altri file di configurazione.

Il punto di scorciatoia laggiù era anche chiamato "gestori", quindi il mio advisor qui faceva riferimento al punto di incisione nell'altro file.

Rinominare il punto di riferimento ha risolto il mio problema.

Altri suggerimenti

La mia ipotesi è che la chiamata lookupTableDao.findById sta ottenendo il tuo oggetto in una sessione, ma il lookupTableDao.saveOrUpdate è diverso - come ottieni < code> Session oggetto, via Spring?

Da dove proviene l'oggetto Column - è già presente nel DB o è nuovo?

Il problema era con la mappatura del filtro nella vista Apri sessione. Stava creando una sessione su getSession E altri su save.

È possibile modificare solo singleSession come falso il valore predefinito è vero

Apparentemente l'uso di Merge probabilmente risolverà il problema

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

Ho avuto lo stesso problema con il mio codice seguente: Volevo aggiornare un determinato negozio Store. Lo stavo recuperando da questo metodo:

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

Quindi, stavo aggiornando il negozio con il seguente metodo:

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

Si scopre che ho ottenuto il "tentativo illegale ..." errore perché la prima sessione dal metodo get non si chiudeva e stavo cercando di aggiornare con l'altra sessione il negozio. La soluzione per me è stata quella di spostare la chiamata per recuperare l'archivio da aggiornare nel metodo di aggiornamento.

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

Se desideri solo una transazione su una parte del tuo codice, puoi utilizzare qualcosa del genere:

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

e nella classe:

@Autowired private SessionFactory sessionFactory;

Più tardi, attorno al codice che dovrebbe fare le cose nella stessa transazione:

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

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

tx.commit();

Lo uso all'interno di un ciclo in alcuni processi batch di lunga durata.

Stavo usando Windows Server IIS e ho appena cambiato la modalità Pipeline gestita AppPool da Integrata a Classica risolto il mio problema.

Grazie

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top