I have a JPA Entity StatsEntity which has a composite primary key that is also as foreign key to another Entity Roster. This is setup as a @OneToOne relationship using @JoinColumns({@JoinColumn…}) annotations.
StatsEntity extends another entity CoreStatsEntity which is setup as @MappedSuperClass where as RosterEntity extends another entity CoreRoster using SINGLE_TABLE inheritance strategy.
@Entity
@Table(name = "Stats")
@IdClass(value = StatsEntity.Key.class)
public class StatsEntity extends CoreStatsEntity implements
Stats {
@Id
private Integer competitionId;
@Id
private Integer playerId;
@Id
private Integer teamId;
@OneToOne
@JoinColumns({
@JoinColumn(name = "competitionId", referencedColumnName = "competitionId", insertable = false, updatable=false),
@JoinColumn(name = "playerId", referencedColumnName = "personId", insertable = false, updatable=false),
@JoinColumn(name = "teamId", referencedColumnName = "teamId", insertable = false, updatable=false) })
private RosterEntity roster;
....
}
StatsEntity.Key
@Embeddable
public static class Key implements Serializable {
private static final long serialVersionUID = -7349082038890396790L;
@Column(name = "competitionId", insertable = false, updatable = false)
private Integer competitionId;
@Column(name = "playerId", insertable = false, updatable = false)
private Integer playerId;
@Column(name = "teamId", insertable = false, updatable = false)
private Integer teamId;
public Key() {
super();
}
public Key(int competitionId, int playerId, int teamId) {
this.competitionId = Integer.valueOf(competitionId);
this.playerId = Integer.valueOf(playerId);
this.teamId = Integer.valueOf(teamId);
}
public int getTeamId() {
return teamId.intValue();
}
public void setTeamId(int teamId) {
this.teamId = Integer.valueOf(teamId);
}
public int getPlayerId() {
return playerId.intValue();
}
public void setPlayerId(int playerId) {
this.playerId = Integer.valueOf(playerId);
}
public int getCompetitionId() {
return competitionId.intValue();
}
public void setCompetitionId(int CompetitionId) {
this.competitionId = Integer.valueOf(CompetitionId);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object object) {
if (object == this) {
return true;
}
if (!(object instanceof Key)) {
return false;
}
Key other = (Key) object;
return Utils.equals(other.getTeamId(), this.getTeamId())
&& Utils.equals(other.getPlayerId(), this.getPlayerId())
&& Utils.equals(other.getCompetitionId(),
this.getCompetitionId());
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Utils.hashCode(this.teamId, this.playerId,
this.competitionId);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return Utils.toString("CompetitionPlayerStatsEntity.Key",
this.teamId, this.playerId, this.competitionId);
}
}
CoreStatsEntity.java
@MappedSuperclass
public abstract class CoreStatsEntity
{}
RosterEntity
@Entity
@DiscriminatorValue("20")
public class RosterEntity extends
CoreRosterEntity {
//.... attributes, getters, setters
}
CoreRosterEntity.java
@Entity
@DiscriminatorValue("0")
@Table(name="Roster")
@IdClass(CoreRoster.Key.class)
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="discriminator", discriminatorType=DiscriminatorType.INTEGER)
public class CoreRosterEntity {
private static final long serialVersionUID = 1521639115446682871L;
@Id
private Integer competitionId;
@Id
private Integer teamId;
@Id
private Integer playerId;
//.. getters, setters and other attributes
}
CoreRoster.Key.class inside CoreRoster.java
@Embeddable
public static class Key implements Serializable {
private static final long serialVersionUID = 2L;
@Column(name="competitionId", nullable=false)
private Integer competitionId;
@Column(name="teamId", nullable=false)
private Integer teamId;
@Column(name="personId", nullable=false)
private Integer playerId;
public Key() {
super();
}
public Key(int competitionId, int teamId, int playerId) {
this.competitionId = Integer.valueOf(competitionId);
this.teamId = Integer.valueOf(teamId);
this.playerId = Integer.valueOf(playerId);
}
public int getPlayerId() {
return playerId.intValue();
}
public void setPlayerId(int playerId) {
this.playerId = Integer.valueOf(playerId);
}
public int getTeamId() {
return teamId.intValue();
}
public void setTeamId(int teamId) {
this.teamId = Integer.valueOf(teamId);
}
public int getCompetitionId() {
return this.competitionId.intValue();
}
public void setCompetitionId(int competitionId) {
this.competitionId = Integer.valueOf(competitionId);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object object) {
if (object == this) { return true; }
if (!(object instanceof Key)) { return false; }
Key other = (Key) object;
return Utils.equals(other.getCompetitionId(), this.getCompetitionId()) &&
Utils.equals(other.getTeamId(), this.getTeamId()) &&
Utils.equals(other.getPlayerId(), this.getPlayerId());
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Utils.hashCode(this.competitionId, this.teamId,
this.playerId);
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return Utils.toString("CoreRoster.Key",
this.competitionId, this.teamId,
this.playerId);
}
}
When I persist StatsEntity, it gets persisted. But when I try to find it using the primary key it gives me an error:
StatsEntity playerStats = new StatsEntity();
//set all values
this.persist(playerStats);
entityManager.find(StatsEntity.class, playerStats.getId()); //getId returns the composite primary key
java.lang.IllegalArgumentException: Provided id of the wrong type for class com.sports.RosterEntity. Expected: class com.sports.CoreRoster$Key, got class com.espn.sports.StatsEntity$Key
My first question here is, is the @OneToOne mapping I have given correct or not?
If it is correct then why this error appears when I try to find the entity using primarykey.
You haven’t posted full source code, especially of your primary key class, but you’ve mapped foreign key as read-only, which is required when single column is mapped more than once.
I see however that you id columns are exactly the same 3 columns that are foreign key to RosterEntity, rights? In that case this RosterEntity should be your ID, which would simplify your design.
What is the return type of your getId() method? The problem is propably with definition or usage of IdClass.