Hello everybody,
I've got a little problem using composite ID when refering in a ManyToOne association.
In my application there are sites where the ID consists only of the name:
Code:
@Entity
public class PokerSite {
@Id
private String siteName;
public String getSiteName() {
return siteName;
}
public void setSiteName(String siteName) {
this.siteName = siteName;
}
private PokerSite() {}
public PokerSite(String siteName) {
this.siteName = siteName;
}
// implementation of hashcode and equals
}
Then I have a player who's ID is a composite of her name and the site she's playing on:
Code:
@Entity
@IdClass(de.scumm.pokertool.core.model.PlayerId.class)
public class Player implements Serializable {
private static final long serialVersionUID = 7947461531672383035L;
public static final Player UNKNOWN = new Player("N/A", new PokerSite("unknown Site"));
@Id
private String name;
@Id
@ManyToOne(targetEntity=de.scumm.pokertool.core.model.PokerSite.class, cascade = {CascadeType.ALL})
@JoinTable(name="Person_Site",
joinColumns={@JoinColumn(name="name")})
private PokerSite site;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PokerSite getSite() {
return site;
}
public void setSite(PokerSite site) {
this.site = site;
}
/* constructor */
private Player() {}
public Player(String name, PokerSite site) {
this.name = name;
this.site = site;
}
// implementation of hashcode and equals
}
with the following IdClass
Code:
public class PlayerId implements Serializable {
private static final long serialVersionUID = -5365195885916675825L;
private String name;
@ManyToOne(targetEntity=de.scumm.pokertool.core.model.PokerSite.class, cascade = {CascadeType.ALL})
@JoinTable(name="Person_Site",
joinColumns={@JoinColumn(name="name", insertable=false, updatable=false)})
private PokerSite site;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PokerSite getSite() {
return site;
}
public void setSite(PokerSite site) {
this.site = site;
}
@Override
public boolean equals(Object o) {
if (o instanceof Player) {
Player otherPlayer = (Player)o;
return name.equals(otherPlayer.getName())
&& site.equals(otherPlayer.getSite());
}
return false;
}
@Override
public int hashCode() {
return (name).hashCode();
}
}
I now try to create an action for a player in which the Player is not even a ID such as the following:
Code:
@Entity
public class Action {
// some constants defined up here
@Id @GeneratedValue
private Long id;
(targetEntity=de.scumm.pokertool.core.model.Player.class, cascade={CascadeType.ALL})
@JoinTable(name="Action_Player",
joinColumns={@JoinColumn(name="action")},
inverseJoinColumns={@JoinColumn(name="name"), @JoinColumn(name="site")})(name="site")})
private Player player;
private String type;
private float value;
public Action() {}
public Long getId() {
return id;
}
@SuppressWarnings("unused")
private void setId(Long id) {
this.id = id;
}
public Player getPlayer() {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
// some more functions...
}
When I try to persist an Action with Person set and within the Person a valid site I get the following Exception:
Code:
org.hibernate.AnnotationException: A component cannot hold properties split into 2 different tables: de.scumm.pokertool.core.model.Player.id
at org.hibernate.cfg.ComponentPropertyHolder.addProperty(ComponentPropertyHolder.java:43)
at org.hibernate.cfg.AnnotationBinder.bindManyToOne(AnnotationBinder.java:1808)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1260)
at org.hibernate.cfg.AnnotationBinder.fillComponent(AnnotationBinder.java:1671)
at org.hibernate.cfg.AnnotationBinder.bindId(AnnotationBinder.java:1704)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:663)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:452)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:268)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1286)
...
I'm not to sure where to start to get around this problem. Obviously I try to avoid to save a player over and over again but as the two person can play with the same name on different sites I'll have to take the site into account as well to generate the ID for a player.
I'm not sure how to resolve this problem and any help would be appreciated.
Thanks everone,
Marc