dimas wrote:
Hm...
Could you try to use <map> instead of <set>? I believe <map> should automatically enforce PK.
Not sure about two-way. Probably, it will work but I wouldn't do that - this becomes ambigous because you will have two sets (set of Groups for User and set of Users for group). I think it is almost impossible for Hibernate to track changes made to these sets because they can conflict.
And about duplicates: hard to guess without you mappings/sources. Have you read FAQ? Is everything Ok with <id>, unsaved-value, equals() etc?
Here's the user mapping (with a number of non-relevant bits deleted):
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<hibernate-mapping>
<class
name="com.avalon.seaview.domain.User"
table="seaviewuser"
>
<!-- <cache usage="read-only"/> -->
<id name="userId" type="java.lang.String" column="UserId" length="20">
<generator class="assigned"/>
</id>
<set name="userGroups" lazy="true" table="usergroups">
<key column="UserId" />
<composite-element class="com.avalon.seaview.domain.UserGroup">
<property name="userJoinDate" column="UserJoinDate" type="java.util.Date" />
<property name="userEndDate" column="UserEndDate" type="java.util.Date"/>
<many-to-one name="group" class="com.avalon.seaview.domain.Group" column="GroupId" not-null="true"/>
</composite-element>
</set>
</class>
</hibernate-mapping>
This is the user class (again with bits deleted):
Code:
public class User implements Serializable
{
private String userId;
private Set userGroups;
public String getUserId()
{
return this.userId;
}
public void setUserId( String userId )
{
this.userId = userId;
}
public Set getUserGroups()
{
return this.userGroups;
}
public void setUserGroups( Set userGroups )
{
this.userGroups = userGroups;
}
public boolean equals( Object other )
{
if ( !( other instanceof User ) ) return false;
User castOther = (User) other;
return new EqualsBuilder()
.append( this.getUserId(), castOther.getUserId() )
.isEquals();
}
public int hashCode()
{
return new HashCodeBuilder()
.append( getUserId() )
.toHashCode();
}
}
UserGroup table:
Code:
public class UserGroup implements Serializable
{
private Date userJoinDate;
private Date userEndDate;
private Group group;
public UserGroup()
{
}
public Date getUserJoinDate()
{
return this.userJoinDate;
}
public void setUserJoinDate( Date userJoinDate )
{
this.userJoinDate = userJoinDate;
}
public Date getUserEndDate()
{
return this.userEndDate;
}
public void setUserEndDate( Date userEndDate )
{
this.userEndDate = userEndDate;
}
public Group getGroup()
{
return group;
}
public void setGroup( Group group )
{
this.group = group;
}
public boolean equals( Object o )
{
if ( this == o ) return true;
if ( !( o instanceof UserGroup ) ) return false;
final UserGroup userGroup = (UserGroup) o;
if ( group != null ? !group.equals( userGroup.group ) : userGroup.group != null ) return false;
return true;
}
public int hashCode()
{
return ( group != null ? group.hashCode() : 0 );
}
public String toString()
{
return "com.avalon.seaview.domain.UserGroup{" +
"userJoinDate=" + userJoinDate +
", userEndDate=" + userEndDate +
"}";
}
}
One iffy thing I can think of might be to do with the userGroup equals and hashcode implementations. The couldn't fine a reference in the manual for what to do with composite equals() and hashcode(). I tried including all the fields but the result was the same.