Cascade delete and ternary association after upgrade
Description
Attachments
Activity

Brett MeyerJuly 8, 2014 at 3:11 PM
Bulk rejecting stale issues. If this is still a legitimate issue on ORM 4, feel free to comment and attach a test case. I'll address responses case-by-case. Thanks!

Brett MeyerApril 7, 2014 at 5:41 PM
In an effort to clean up, in bulk, tickets that are most likely out of date, we're transitioning all ORM 3 tickets to an "Awaiting Test Case" state. Please see http://in.relation.to/Bloggers/HibernateORMJIRAPoliciesAndCleanUpTactics for more information.
If this is still a legitimate bug in ORM 4, please provide either a test case that reproduces it or enough detail (entities, mappings, snippets, etc.) to show that it still fails on 4. If nothing is received within 3 months or so, we'll be automatically closing them.
Thank you!

Carl GilbertJuly 4, 2007 at 7:59 PM
The varHolderMap in the DBVariant class is the one that causes the problem. When I try to delete a VarCollHolder from it it excepts.

Carl GilbertJuly 4, 2007 at 7:58 PM
I am using postgres 8.1 with driver 8.1-409 and java 1.5.0_11
Same problem. Fell back to 3.2.0.ga and its working again.
My mapping is just about the same.
dbvariant.hbm.xml
[code]
<hibernate-mapping>
<joined-subclass name="com.rgdsft.hib.core.DBVariant" table="VARIANT" extends="com.rgdsft.hib.core.DBNamedObject">
<key column="OBJECT_ID"/>
<properties name="uniqueVirtualSysNameConstraint" unique="true">
<property name="name" not-null="true" type="string"/>
<many-to-one name="project" class="com.rgdsft.hib.core.DBProject" column="ProjectID" not-null="true" lazy="proxy"/>
</properties>
<!-- problem here because we do not want the variant referenced by the
variantcollholder. That would interfere with the serialization. Since we
do not put the variant in the holder, we can not get hibernate to create the
foreign key constraints that I would want here. What I want is unique
(variant,system)
also maybe not-null in the systemID key?
-->
<map name="varholderMap" table="VARHOLDER_MAP" access="field" cascade="all,delete-orphan">
<key column="DBVariant_ID" not-null="true"/>
<map-key-many-to-many column="KEY_SystemID" class="com.rgdsft.hib.core.DBSystem"/>
<one-to-many class="com.rgdsft.hib.core.VariantCollHolder"/>
</map>
</joined-subclass>
</hibernate-mapping>
<hibernate-mapping>
<joined-subclass name="com.rgdsft.hib.core.DBNamedObject" abstract="true" extends="com.rgdsft.hib.core.DBObject">
<key column="OBJECT_ID"/>
<map name="properties" table="PROPERTIES" access="field">
<key column="DBNamedObject_ID" not-null="true"/>
<map-key-many-to-many column="PROPERTY_ID" class="com.rgdsft.hib.core.DBPropertyType"/>
<element column="PROPERTY_VALUE" type="string" not-null="true"/>
</map>
</joined-subclass>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.rgdsft.hib.core.DBObject" abstract="true">
<id name="id" column="OBJECT_ID">
<generator class="native"/>
</id>
<property name="identifier" not-null="true" unique="true"/>
</class>
</hibernate-mapping>
/code
VariantCollHolder.hbm.xml
[code]
<hibernate-mapping>
<class name="com.rgdsft.hib.core.VariantCollHolder" table="VARIANTCOLLHOLDER" lazy="false">
<id name="id" type="long">
<generator class="native"/>
</id>
<!-- no cascading here since we will only ever deal in remove/add from
collection and deal in querying values from the comp instance -->
<set name="instances" table="COMPINST_VARIANT" lazy="false" access="field">
<key column="VariantID"/> <!-- change to varCollHolderID -->
<many-to-many column="CompinstanceID" class="com.rgdsft.hib.core.DBComponentInstance"/>
</set>
<!-- no cascading here since we will only ever deal in remove/add from
collection and deal in querying values from the comp instance -->
<set name="connections" table="CONNECTION_VARIANT" lazy="false" access="field">
<key column="VariantID"/> <!-- change to varCollHolderID -->
<many-to-many column="ConnectionID" class="com.rgdsft.hib.core.DBFunctionConnection"/>
</set>
</class>
</hibernate-mapping>
/code
And a few classes
[code]
public class DBVariant extends DBNamedObject {
private String name;
private DBProject project;
private Map<DBSystem,VariantCollHolder> varholderMap = new HashMap<DBSystem,VariantCollHolder>();//not in default fetch
public DBVariant(String name, DBProject project, Long identifier) {
super(identifier);
assert name != null;
assert project != null;
this.name = name;
this.project = project;
}
DBVariant(){
}
//edited-Not a test case
}
public final class VariantCollHolder implements Serializable {
private static final long serialVersionUID = 1L;
/*
Hibernate spec version 3.2.0.ga section 4.1.2 states that transitive
reattachment of detached objects requires an identifier. So we have one.
*/
private Long id; // identifier
/**The set of component instances in the associated variant.
*/
private Set<DBComponentInstance> instances = new HashSet<DBComponentInstance>();
/**The set of connections in the associated variant.
*/
private Set<DBFunctionConnection> connections = new HashSet<DBFunctionConnection>();
private transient boolean dirty;
public VariantCollHolder() {
}
/**
@return the instances
*/
public Set<DBComponentInstance> getInstances() {
return instances;
}
/**
* @param instances the instances to set
*/
void setInstances(Set<DBComponentInstance> instances) {
this.instances = instances;
}
/**
* @return the connections
*/
public Set<DBFunctionConnection> getConnections() {
return connections;
}
/**
* @param connections the connections to set
*/
void setConnections(Set<DBFunctionConnection> connections) {
this.connections = connections;
}
public boolean isDirty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
}
public abstract class DBNamedObject extends DBObject {
private Map<DBPropertyType,String> properties = new HashMap<DBPropertyType,String>();//not in default fetch
public DBNamedObject(Long identifier) {
super(identifier);
}
DBNamedObject(){
}
/************************ Begin Property Stuff ****************************/
public final Set<DBPropertyType> getPropertyKeys(){
return properties.keySet();
}
/*
This probably works but is less efficient than calling for the key set
and constructing objects that way. At least to the WAD object because
we construct a map here, and they will have to construct a new map there.
*/
public Map<DBPropertyType,String> getProperties(){
return properties;
}
public String getProperty(DBPropertyType key) {
return properties.get(key);
}
public String setProperty(DBPropertyType key, String value){
return properties.put(key,value);
}
/************************ End Property Stuff ******************************/
public abstract String getName();
public abstract void setName(String name);
}
public abstract class DBObject {
/*
Hibernate spec version 3.2.0.ga section 4.1.2 states that transitive
reattachment of detached objects requires an identifier. So we have one.
*/
private Long id;
private Long identifier;
/*An object is dirty when it is modified.
*/
private transient boolean dirty;
DBObject(){
}
public DBObject(Long identifier) {
assert identifier != null;
this.identifier = identifier;
}
private void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public Long getIdentifier() {
return identifier;
}
private void setIdentifier(Long identifier) {
this.identifier = identifier;
}
public boolean isDirty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
//we need a system based on something that does not change and is assignable at commit time
//I think identifier does not change and is assignable at commit time!
@Override
public boolean equals(Object obj) {
if(obj instanceof DBObject){
return ((DBObject)obj).identifier.equals(identifier);
}
return false;
}
@Override
public int hashCode() {
return identifier.hashCode();
}
/**
Do not show hashcode if equals is not based on hashcode
*/
@Override
public String toString() {
return "(" + getClass().getSimpleName() + "::" + identifier +"@" + super.hashCode() +")";
}
}
/code
My classes:
public class Product {
private long id;
private String name;
private Map/<Attribute,AttributeValue>/ attributeValues;
//getters/setters/hashcode/equals
}
public class AttributeValue {
private long id;
private String value;
private Product product;
private Attribute attribute;
//getters/setters/hashcode/equals
}
public class Attribute {
private long id;
private String name;
//getters/setters/hashcode/equals
}
Fragment of mapping:
<class name="Product">
<id name="id" column="id" type="long" unsaved-value="0">
<generator class="native"/>
</id>
<property name="name" not-null="true"/>
<map name="attributeValues" lazy="true" inverse="false" cascade="all-delete-orphan">
<key column="product_id" not-null="true"/>
<map-key-many-to-many column="attribute_id" class="Attribute"/>
<one-to-many class="AttributeValue"/>
</map>
</class>
... and my exception after upgrading hibernate in my application.
2007-06-27 20:08:54 org.hibernate.property.BasicPropertyAccessor$BasicGetter get
SEVERE: IllegalArgumentException in class: com.mycompany.Attribute, getter method of property: id
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.mycompany.Attribute.id
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:171)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:183)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3591)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:3307)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:181)
at org.hibernate.engine.ForeignKeys$Nullifier.isNullifiable(ForeignKeys.java:137)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:69)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:47)
at org.hibernate.event.def.DefaultDeleteEventListener.deleteEntity(DefaultDeleteEventListener.java:248)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:141)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:775)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:758)
at org.hibernate.engine.CascadingAction$2.cascade(CascadingAction.java:121)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.DefaultDeleteEventListener.cascadeBeforeDelete(DefaultDeleteEventListener.java:307)
at org.hibernate.event.def.DefaultDeleteEventListener.deleteEntity(DefaultDeleteEventListener.java:246)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:141)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:52)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:766)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:744)
I've tried many versions of hibernate using test from attachment
( mvn -Dhibernate.version=<version> clean compile test ) and I think that
bug was introduced between 3.2.0.ga and 3.2.1.ga