i'm using JBoss TreeCache as the 2nd level cache with these 3 beans, which form a one-many-one relation:
Car
Code:
@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
Code:
@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
Code:
@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 entity, everything works as expected, unless i access a Car entity which was previously cached, because it looks like its cached collection of "FaxToCar" references an instance of "Fax2Car", which was deleted because of "CascadeType.DELETE_ORPHAN".
The stacktrace looks like this:
Code:
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:
Code:
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");
}
Bug or Feature ?
TIA
M.