2008-10-21 21 views
10

Próbuję dodać pojo do kolekcji w innym pojo. Jestem pewien, że popełniam głupią pomyłkę, ale nie mogę wymyślić, jak ją rozwiązać.Nielegalna próba skojarzenia kolekcji z dwiema otwartymi sesjami

Mam tablicowanie Pojo który zawiera listę kolumny:

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

W mojej konfiguracji hibernacji mam:

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

W moim pliku config Wiosny mam:

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

I na koniec kod, w którym wszystko zawiedzie w mojej klasie menedżera (com.foo.LookupTableManager):

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

Zmienna lookupTablesDao odnosi się tutaj do prostej klasy DAO, która rozszerza HibernateDaoSupport.

Błąd pojawia się:

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, rozumiem podstawowe wiadomości dostaję. Ale nie rozumiem, skąd biorę drugą sesję ... Czy ktoś może mi w tym pomóc?

używam hibernacji 3.2.6.ga Spring 2.5.5 i Tomcat 6.0

Odpowiedz

4

O cholera, rozwiązanie było trochę zbyt proste. Okazuje się, że nie miałem żadnej transakcji. Użyłem prawie tej samej konfiguracji transakcji w jednym z moich innych plików konfiguracyjnych. Punkt przecięcia był również nazywany "menedżerami", więc mój doradca tutaj odwoływał się do punku cięcia w drugim pliku. Zmiana nazwy punktu cięcia rozwiązała mój problem.

2

Domyślam się, że wezwanie lookupTableDao.findById jest coraz obiekt w jednej sesji, ale lookupTableDao.saveOrUpdate jest inny - jak otrzymujesz obiekt Session, przez Spring?

Skąd się bierze obiekt Column - czy to już w DB lub nowym?

+0

[Edytuj, przeniósł odpowiedź na komentarz]: Dostaję sesję metodą getSession() z org.springframework.orm.hibernate.support.HibernateDaoSupport. Powinno to zwrócić sesję z bieżącej transakcji ... Obiekt Kolumna jest nowo utworzony. –

1

Problem dotyczył odwzorowania filtra Open Session In view. Tworzyło sesję na getSession I inne na zapis.

można zmienić tylko singleSession jako fałszywy domyślne to prawda

1

Widocznie za pomocą seryjnej będzie prawdopodobnie rozwiązać problem

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

Jeśli chcesz tylko transakcji na części kodu można użyć coś tak:

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

aw klasie:

@Autowired private SessionFactory sessionFactory; 

Później wokół kodu, który powinien zrobić rzeczy w tej samej transakcji:

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

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

tx.commit(); 

Używam tego wewnątrz pętli w niektórych długo uruchomionych zadań wsadowych.

1

Miałem ten sam problem z następującym kodem: Chciałem zaktualizować określony sklep z encji. Byłem pobierania go z tej metody:

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

Potem było aktualizowanie zapisać w następujący sposób:

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

Okazuje się, mam „Niedozwolony próbę ...” błąd, ponieważ pierwsza sesja z metody get nie kończyła się, a ja próbowałem zaktualizować drugą sesję sklepu. Rozwiązaniem dla mnie było przeniesienie wywołania pobierania magazynu do aktualizacji w metodzie aktualizacji.

@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

używałem Windows Server IIS i po prostu zmieniając Zarządzane tryb Pipeline AppPool z wbudowanych klasycznych rozwiązać mój problem.

Dzięki