在 JPA 中使用继承时的复合外键问题
Posted
技术标签:
【中文标题】在 JPA 中使用继承时的复合外键问题【英文标题】:Composite Foreign Key Issue while using Inheritance in JPA 【发布时间】:2011-12-29 13:52:55 【问题描述】:我有一个 JPA 实体 StatsEntity,它有一个复合主键,它也是另一个实体名册的外键。这是使用 @JoinColumns(@JoinColumn...) 注释设置为 @OneToOne 关系。
StatsEntity 扩展了另一个实体 CoreStatsEntity,它设置为 @MappedSuperClass 其中 RosterEntity 使用 SINGLE_TABLE 继承策略扩展了另一个实体 CoreRoster。
@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
名册实体
@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.java 中的CoreRoster.Key.class
@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);
当我持久化 StatsEntity 时,它会被持久化。但是当我尝试使用主键找到它时,它给了我一个错误:
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
我的第一个问题是,我给出的@OneToOne 映射是否正确? 如果正确,那么当我尝试使用主键查找实体时为什么会出现此错误。
【问题讨论】:
【参考方案1】:您尚未发布完整的源代码,尤其是您的主键类的源代码,但您已将外键映射为只读,这在多次映射单个列时是必需的。
但是,我看到您的 id 列与作为 RosterEntity 的外键的 3 列完全相同,对吗?在这种情况下,这个 RosterEntity 应该是您的 ID,这将简化您的设计。
getId() 方法的返回类型是什么?问题可能与 IdClass 的定义或用法有关。
【讨论】:
已编辑问题。 getId的返回类型是Object,但我返回的是StatsEntity.Key的对象。让我试试你的建议 Roster.Key 不能作为 ID,因为其中的列名称不同。(personId 而不是 playerId) 对 DB 列添加了一个小改动(感谢 DBA),现在我将密钥设置为 RosterEntity。工作。谢谢以上是关于在 JPA 中使用继承时的复合外键问题的主要内容,如果未能解决你的问题,请参考以下文章
在复合键中使用 JoinColumns 时的 TypeDescriptor 错误