JPA:如何使用派生的IdClass实现复合主键?

时间:2015-09-18 12:08:03

标签: java jpa eclipselink

我正在使用JPA实体实现以下表结构,其中显示的属性表示PK / FK列。 protocolId是自动生成的,并在调用persist()之前在所有实体中设置为null。整个结构立即存储。

Table relationships

使用help of a stackoverflow userJPA 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的身份?

1 个答案:

答案 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'列添加到项目表并将其用作主键(并在外键列上添加复合唯一约束)。