[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2690) Cascade delete and ternary association after upgrade

Carl Gilbert (JIRA) noreply at atlassian.com
Wed Jul 4 13:58:52 EDT 2007


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2690?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_27407 ] 

Carl Gilbert commented on HHH-2690:
-----------------------------------

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]

> Cascade delete and ternary association after upgrade
> ----------------------------------------------------
>
>                 Key: HHH-2690
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2690
>             Project: Hibernate3
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 3.2.1, 3.2.2, 3.2.3, 3.2.4, 3.2.4.sp1
>         Environment: hsqldb, jvm 1.6.0_01-ea, ubuntu
>            Reporter: Przemek Dyk
>         Attachments: manytest.zip
>
>
> 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

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list