Hello.
I have modeled a unary (singular) association on my entity ContentProviderAccount with an association class
(implemented as a join/link table).
My use case is that each ContentProviderAccount entity has a list of fans and a list of favorites (which are ContentProviderAccount entities as well)
ContentProviderAccount A can add ContentProviderAccount B as a favorite (A is then B's fan).
Also, ContentProviderAccount B can add ContentProviderAccount A as a favorite (B is then A's fan).
The association is not necessarily mutual and two associations can exist between two ContentProviderAccounts.
Each association has a creation date and a number (not suitable as a primary key though, because it is not unique)
This is my implementation of the assocoation class: (inspired by listing 7.1 in the book 'Java persistence with Hibernate', chapter 7.2.3)
Code:
@javax.persistence.Entity
@javax.persistence.Table(name = "FANS2FAVORITES")
public class FanFavoriteAssociation implements java.io.Serializable, Comparable<FanFavoriteAssociation> {
@Embeddable
public static class Id implements Serializable {
@Column(name = "CONTENT_PROVIDER_ACCOUNT_FAN_ID")
private Long fan;
@Column(name = "CONTENT_PROVIDER_ACCOUNT_FAVORITE_ID")
private Long favorite;
public Id() {
}
public Id(Long fanId, Long favoriteId) {
this.fan = fanId;
this.favorite = favoriteId;
}
//equals and hashCode
}
@javax.persistence.Column(name = "CREATION_DATE")
private java.util.Date creationDate;
@javax.persistence.Column(name = "NUMBER")
private java.lang.Long number;
@EmbeddedId
private Id id = new Id();
// --------- Relationship Definitions -----------
@javax.persistence.ManyToOne
@javax.persistence.JoinColumn(name = "CONTENT_PROVIDER_ACCOUNT_FAN_ID", insertable = false, updatable = false)
private ContentProviderAccount contentProviderAccountFan;
@javax.persistence.ManyToOne
@javax.persistence.JoinColumn(name = "CONTENT_PROVIDER_ACCOUNT_FAVORITE_ID", insertable = false, updatable = false)
private ContentProviderAccount contentProviderAccountFavorite;
public FanFavoriteAssociation() {
}
public FanFavoriteAssociation(java.util.Date creationDate, java.lang.Long number) {
setCreationDate(creationDate);
setNumber(number);
}
public FanFavoriteAssociation(ContentProviderAccount contentProviderAccountFan,
ContentProviderAccount contentProviderAccountFavorite, java.util.Date creationDate, Long number) {
this.contentProviderAccountFan = contentProviderAccountFan;
this.contentProviderAccountFavorite = contentProviderAccountFavorite;
this.creationDate = creationDate;
this.number = number;
// set identifier values
this.id.fan = contentProviderAccountFan.getId();
this.id.favorite = contentProviderAccountFavorite.getId();
// guarantee referential integrity
System.out.println("guarantee referential integrity on fans");
contentProviderAccountFan.getFans().add(this); contentProviderAccountFan.getFavorites().add(this);
System.out.println("guarantee referential integrity on favorites");
contentProviderAccountFavorite.getFavorites().add(this);
contentProviderAccountFavorite.getFans().add(this);
// getter and setter methods
}
// getters and setters...
// equals and hashCode...
// toString and compareTo...
}
the entity ContentProviderAccount has a OneToMany collection for fans and for favorites.
Code:
@javax.persistence.OneToMany(mappedBy = "contentProviderAccountFan")
public java.util.List<FanFavoriteAssociation> getFans()
{
return this.fans;
}
@javax.persistence.OneToMany(mappedBy = "contentProviderAccountFavorite")
public java.util.List<FanFavoriteAssociation> getFavorites()
{
return this.favorites;
}
I create an association where userA is fan to userB by doing:
Code:
FanFavoriteAssociation fan2favorite = new FanFavoriteAssociation(userA, userB, new java.util.Date(System.currentTimeMillis()), number);
fanFavoriteAssociationDao.create(fan2favorite);
this conceptually means that userA now is fan to userB and userB is favorite to userA.
This is all well except for when I want to add another association with the opposite case (which is perfectly ok in my concept model).
namely when userB is fan to userA.
This results in a duplicate key SQL error because hibernate tries to create a row with the same values (which is strange becuase I reverse the parameters to the fanfavoriteassociation constructor).
column A(pk) column B(pk)
1 2
2 1
These two table rows should not result in duplicate keys, right?
With a manual insert sql query this works well but Hibernate fails (i think in the dao where I call create on the entity manager).
Is this association class insufficient for this requirement or have I missed something obvious?
thanks in advice,
Fredrik