我正在使用JPA实体实现以下表结构,其中显示的属性表示PK / FK列。 protocolId是自动生成的,并在调用persist()
之前在所有实体中设置为null。整个结构立即存储。
使用help of a stackoverflow user和JPA spec,我在Position
中解析了派生身份:
@Entity
@Table(name="...")
@IdClass(PositionID.class)
public class Position {
@Id
@Column(name = "POSITION_ID")
private int positionId;
@Id
@ManyToOne(...)
@JoinColumn(name="PROTOCOL_ID")
private Protocol protocol;
@OneToMany(mappedBy="position")
private Collection<Item>
}
public class PositionID implements Serializable{
private int protocol;
private int positionId;
}
以上关系有效,但我在Item
中实现派生身份时遇到问题。
这是我根据 2.4.1.3派生身份的例子中的规范编写的版本:
@Entity
@Table(name="...")
@IdClass(ItemId.class)
public class Item {
@Id
@Column(name = "ITEM_NAME")
private String itemName;
@Id
@ManyToOne(...)
@JoinColumns({
@JoinColumn(name="POSITION_ID", referencedColumnName="POSITION_ID"),
@JoinColumn(name="PROTOCOL_ID", referencedColumnName="PROTOCOL_ID")
})
private Position position;
}
public class ItemId implements Serializable {
private String itemName;
private PositionId position;
}
不幸的是,这会导致以下错误:
无效的复合主键规范。主要的名字 主键类[null]中的键字段或属性以及 实体bean类[class ...... Item]必须 对应,它们的类型必须相同。
如何实现Item
的身份?
答案 0 :(得分:2)
我认为您可以使用组合主键!
在您的主要实体(项目)中,您可以使用:
@EmbeddedId
private CombinedPK id;
在CombinedPK中你设置了这个:
@Embeddable // Annotation on class level
public class CombinedPK {
...
@Column(name = "positionId")
private Integer positionId;
@Column(name = "protocolId")
private Integer protocolId;
}
然后可以像往常一样映射CombinedPK中的列,每个列都是自己的。
此外,从@Id
字段中删除position
注释,并将insertable=false, updatable=false
添加到您的@JoinColumn
注释中。
问题在于,在Java模型中,您有(并且需要)来自SQL的相同数据的两种不同表示:您需要对主键进行建模和注释,并且还需要外键关系。 JPA不能很好地处理这个问题,JPA也禁止更改记录的主键。如果您可以更改数据库,您会发现更容易将'SERIAL'列添加到项目表并将其用作主键(并在外键列上添加复合唯一约束)。