Quote:
Then add "bbb" to the collection property on "foo". With POJOs, both "aaa" and "foo" would contain an instance of "bbb". With EMF/MOF, the act of setting "bbb" in "foo"'s collection property will *automatically* remove "bbb" from "aaa" since containment means that an instance of the model object can only be contained by one parent.
I'm dealing with the same problem, however, I decided to place my subclasses of sets as inner classes of the from-end in the association.
Basically this problem will dissapere if one don't use lazy loading. It would also appeare using bidirectional associations with no multiplicity.
I didn't try to see if this worked yet, but I guess that it will not. Greatfull for any help, thoughts and comments.
Consider this class diagram:
Code:
[Human]-- {2} +parent +child {0..*} --[Human]
And this is the code that I hope would represent that:
Code:
package se.snigel.silvertejp.test.hibernate;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.collection.PersistentSet;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.usertype.UserCollectionType;
/**
* @hibernate.class lazy="true" table="Human"
*/
public class Human
{
private java.lang.Long primaryKey = null;
private se.snigel.silvertejp.test.hibernate.Human.ChildSet children = new ChildSet();
private se.snigel.silvertejp.test.hibernate.Human.ParentSet parents = new ParentSet();
/**
* @hibernate.id column="Human_PK" type="long" unsaved-value="null"
* generator-class="native"
*/
public java.lang.Long getPrimaryKey()
{
return this.primaryKey;
}
public void setPrimaryKey(java.lang.Long primaryKey)
{
this.primaryKey = primaryKey;
}
/**
* @hibernate.set lazy="true" cascade="all"
* @hibernate.many-to-many inverse="true" table="parentHuman_childHuman_"
* column="parent_FK"
* class="se.snigel.silvertejp.test.hibernate.Human"
* name="children"
*/
public ChildSet getChildren()
{
return this.getChildren();
}
public void setChildren(ChildSet children)
{
this.children = children;
}
/**
* @hibernate.set lazy="true" cascade="all"
* @hibernate.many-to-many inverse="true" table="parentHuman_childHuman_"
* column="child_FK"
* class="se.snigel.silvertejp.test.hibernate.Human"
* name="parents"
*/
public ParentSet getParents()
{
return this.getParents();
}
public void setParents(ParentSet parents)
{
this.parents = parents;
}
public boolean equals(java.lang.Object o)
{
if (o == null)
{
return false;
}
if (o == this)
{
return true;
}
if (this.getPrimaryKey() == null)
{
return false;
}
if (!o.getClass().equals(this.getClass()))
{
return false;
}
return this.getPrimaryKey().equals(((se.snigel.silvertejp.test.hibernate.Human) o).getPrimaryKey());
}
public int hashCode()
{
if (getPrimaryKey() != null)
{
return getPrimaryKey().hashCode();
}
else
{
return super.hashCode();
}
}
public class ChildSetUserCollectionType implements UserCollectionType
{
/**
* Instantiate an uninitialized instance of the collection wrapper
*/
public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) throws HibernateException
{
return new PersistentSet(session);
}
/**
* Wrap an instance of a collection
*/
public PersistentCollection wrap(SessionImplementor session, Object collection)
{
return new PersistentSet(session, (ChildSet) collection);
}
/**
* Return an iterator over the elements of this collection - the passed
* collection instance may or may not be a wrapper
*/
public Iterator getElementsIterator(Object collection)
{
return ((ChildSet) collection).iterator();
}
/**
* Optional operation. Does the collection contain the entity instance?
*/
public boolean contains(Object collection, Object entity)
{
return ((ChildSet) collection).contains(entity);
}
/**
* Optional operation. Return the index of the entity in the collection.
*/
public Object indexOf(Object collection, Object entity)
{
return null;
}
/**
* Replace the elements of a collection with the elements of another
* collection
*/
public void replaceElements(Object source, Object target, CollectionPersister persister, Object owner, Map copyCache, SessionImplementor session)
throws HibernateException
{
Set castedTarget = (ChildSet) target;
castedTarget.clear();
castedTarget.addAll((ChildSet) source);
}
/**
* Instantiate an empty instance of the "underlying" collection (not a
* wrapper)
*/
public Object instantiate()
{
return new ChildSet();
}
}
public class ChildSet extends java.util.HashSet
{
public boolean add(java.lang.Object child)
{
se.snigel.silvertejp.test.hibernate.Human member = (se.snigel.silvertejp.test.hibernate.Human) child;
boolean added = super.add(member);
// link other end instance with this instance.
if (added && !member.getParents().contains(se.snigel.silvertejp.test.hibernate.Human.this))
{
member.getParents().add(se.snigel.silvertejp.test.hibernate.Human.this);
}
return added;
}
public boolean remove(java.lang.Object child)
{
se.snigel.silvertejp.test.hibernate.Human member = (se.snigel.silvertejp.test.hibernate.Human) child;
boolean removed = super.remove(member);
// unlink reference in other end
if (removed && member.getParents().contains(se.snigel.silvertejp.test.hibernate.Human.this))
{
member.getParents().remove(se.snigel.silvertejp.test.hibernate.Human.this);
}
return removed;
}
}
public class ParentSetUserCollectionType implements UserCollectionType
{
/**
* Instantiate an uninitialized instance of the collection wrapper
*/
public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) throws HibernateException
{
return new PersistentSet(session);
}
/**
* Wrap an instance of a collection
*/
public PersistentCollection wrap(SessionImplementor session, Object collection)
{
return new PersistentSet(session, (ParentSet) collection);
}
/**
* Return an iterator over the elements of this collection - the passed
* collection instance may or may not be a wrapper
*/
public Iterator getElementsIterator(Object collection)
{
return ((ParentSet) collection).iterator();
}
/**
* Optional operation. Does the collection contain the entity instance?
*/
public boolean contains(Object collection, Object entity)
{
return ((ParentSet) collection).contains(entity);
}
/**
* Optional operation. Return the index of the entity in the collection.
*/
public Object indexOf(Object collection, Object entity)
{
return null;
}
/**
* Replace the elements of a collection with the elements of another
* collection
*/
public void replaceElements(Object source, Object target, CollectionPersister persister, Object owner, Map copyCache, SessionImplementor session)
throws HibernateException
{
Set castedTarget = (ParentSet) target;
castedTarget.clear();
castedTarget.addAll((ParentSet) source);
}
/**
* Instantiate an empty instance of the "underlying" collection (not a
* wrapper)
*/
public Object instantiate()
{
return new ParentSet();
}
}
public class ParentSet extends java.util.HashSet
{
public boolean add(java.lang.Object parent)
{
se.snigel.silvertejp.test.hibernate.Human member = (se.snigel.silvertejp.test.hibernate.Human) parent;
if (this.size() >= 2)
{
throw new ArrayIndexOutOfBoundsException("Max size is set to 2.");
}
boolean added = super.add(member);
// link other end instance with this instance.
if (added && !member.getChildren().contains(se.snigel.silvertejp.test.hibernate.Human.this))
{
member.getChildren().add(se.snigel.silvertejp.test.hibernate.Human.this);
}
return added;
}
public boolean remove(java.lang.Object parent)
{
se.snigel.silvertejp.test.hibernate.Human member = (se.snigel.silvertejp.test.hibernate.Human) parent;
boolean removed = super.remove(member);
// unlink reference in other end
if (removed && member.getChildren().contains(se.snigel.silvertejp.test.hibernate.Human.this))
{
member.getChildren().remove(se.snigel.silvertejp.test.hibernate.Human.this);
}
return removed;
}
}
}