2nd level cache fails with one-many-one relations
bigm25 Mar 28, 2006 4:25 AMi'm using TreeCache as the 2nd level cache with these 3 beans, which form a one-many-one relation:
Car
@Entity @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) @Entity(optimisticLock = OptimisticLockType.VERSION) @Table(name = "CAR") public class Car extends BaseEntity implements java.io.Serializable { private List<FaxToCar> faxes; ..... @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "car") @Cascade(value=CascadeType.DELETE_ORPHAN) @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) public List<FaxToCar> getFaxes() { return faxes; } .... @Transient public String getFaxNameList() { List<FaxToCar> l = getFaxes(); String s = ""; for (FaxToCar car2 : l) { if (s.length() > 0) { s += ", "; } s += car2.getFax().getName(); } return s; } }
FaxToCar
@Entity @Entity(optimisticLock = OptimisticLockType.VERSION) @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) @Table(name = "FAX2CAR") public class FaxToCar extends BaseEntity implements java.io.Serializable { protected int seq; private Car car; private Fax fax; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "car_id") public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "fax_id") public Fax getFax() { return fax; } public void setFax(Fax fax) { this.fax = fax; } public int getSeq() { return seq; } public void setSeq(int seq) { this.seq = seq; } }
Fax
@Entity @Entity(optimisticLock = OptimisticLockType.VERSION) @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) @Table(name = "FAX") public class Fax extends BaseEntity implements java.io.Serializable { private List<FaxToCar> cars; ... @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "fax") @Cascade(value=CascadeType.DELETE_ORPHAN) @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) @OrderBy("seq") public List<FaxToCar> getCars() { return cars; } ...
After i deleted a "Fax", everything works as expected, unless i acces a "Car" which was previously cached, becasue it looks like its cached collection of "FaxToCar" references a now not longer instance of "Fax2Car", which was deleted because of "CascadeType.DELETE_ORPHAN".
The stacktrace looks like this:
10:54:22,171 INFO [STDOUT] Hibernate: select car0_.id as id12_, car0_.version as version12_, car0_.createdBy as createdBy12_, car0_.updatedBy as updatedBy12_,
car0_.createdTime as createdT5_12_, car0_.updatedTime as updatedT6_12_, car0_.gf as gf12_, car0_.typ as typ12_, car0_.hersteller as hersteller12_, car0_.lack a
lack12_, car0_.lack_code as lack11_12_, car0_.polster as polster12_, car0_.polster_code as polster13_12_, car0_.ez as ez12_, car0_.angebotspreis as angebot15_
2_, car0_.vorbesitzer as vorbesi16_12_, car0_.km as km12_, car0_.neupreis as neupreis12_, car0_.behobenerschaden as behoben19_12_, car0_.differenzbesteuert as
iffere20_12_, car0_.verkauft as verkauft12_, car0_.freitext as freitext12_ from CAR car0_ where 1=1 and (car0_.gf like ?)
10:54:22,452 INFO [STDOUT] Hibernate: select faxtocar0_.id as id18_0_, faxtocar0_.version as version18_0_, faxtocar0_.createdBy as createdBy18_0_, faxtocar0_.
pdatedBy as updatedBy18_0_, faxtocar0_.createdTime as createdT5_18_0_, faxtocar0_.updatedTime as updatedT6_18_0_, faxtocar0_.car_id as car8_18_0_, faxtocar0_.f
x_id as fax9_18_0_, faxtocar0_.seq as seq18_0_ from FAX2CAR faxtocar0_ where faxtocar0_.id=?
10:54:22,452 INFO [DefaultLoadEventListener] Error performing load command
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [de.foobar.hfax.entity.fax.FaxToCar#27908]
at org.hibernate.ObjectNotFoundException.throwIfNull(ObjectNotFoundException.java:27)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:128)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:177)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:87)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:891)
at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:859)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:266)
at org.hibernate.type.ManyToOneType.assemble(ManyToOneType.java:177)
at org.hibernate.collection.PersistentBag.initializeFromCache(PersistentBag.java:140)
at org.hibernate.cache.entry.CollectionCacheEntry.assemble(CollectionCacheEntry.java:35)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.initializeCollectionFromCache(DefaultInitializeCollectionEventListener.java:130)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:48)
at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1695)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:246)
at de.foobar.hfax.entity.core.Car.getFaxNameList(Car.java:269)
.....
As a workaround, i'm manually evicting the offending collection out of the cache:
public void removeFax(Fax fax) { manager.remove(fax); manager.flush(); Session hs = ((HibernateSession)manager).getHibernateSession(); hs.getSessionFactory().evictCollection("de.foobar.hfax.entity.core.Car.faxes"); }
Question: Bug or Feature ?
TIA
Marco