我遇到了一个使用多字段主键的数据库。我有一种情况,我有一个主表和详细信息表,其中详细信息表的主键包含字段,也是外键的主表。像这样:
Master primary key fields:
master_pk_1
Details primary key fields:
master_pk_1
details_pk_2
details_pk_3
在Master类中,我们定义了像这样的hibernate / JPA注释:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idGenerator")
@Column(name = "master_pk_1")
private long masterPk1;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name = "master_pk_1", referencedColumnName = "master_pk_1")
private List<Details> details = new ArrayList<Details>();
在详细信息类中,我已经定义了id和back引用,如下所示:
@EmbeddedId
@AttributeOverrides( {
@AttributeOverride( name = "masterPk1", column = @Column(name = "master_pk_1")),
@AttributeOverride(name = "detailsPk2", column = @Column(name = "details_pk_2")),
@AttributeOverride(name = "detailsPk2", column = @Column(name = "details_pk_2")) })
private DetailsPrimaryKey detailsPrimaryKey = new DetailsPrimaryKey();
@ManyToOne
@JoinColumn(name = "master_pk_1", referencedColumnName = "master_pk_1", insertable=false)
private Master master;
所有这一切的目标是我可以创建一个新的主人,为它添加一些细节,并且在保存时,JPA / Hibernate将在masterPk1字段中为master生成新的id,并自动将其传递给详细记录,将其存储在DetailsPrimaryKey类的匹配masterPk1字段中。至少这就是我一直在寻找的文档所暗示的内容。
实际发生的事情是,hibernate似乎在核心创建和更新数据库中的记录,但不会将密钥传递给内存中的详细信息类。相反,我必须自己手动设置它。
我还发现,如果没有将insertable=true
添加到master的后向引用中,那么hibernate将创建在insert语句中列出两次master_pk_1字段的sql,导致数据库抛出异常。
我的问题很简单,这种注释安排是否正确?或者有更好的方法吗?
答案 0 :(得分:2)
您是否也可以添加DetailsPrimaryKey映射?
您的映射中看起来很奇怪的是您在详细信息故事中映射了两次'master_pk_1'列。通过添加insertable = false选项,现在插入工作,但我想更新仍然不起作用(事实上,当你在一个实体中多次映射列时,你必须使用insertable = false,updatable = false注释除了其中一个之外的所有列) / p>
为了纠正这个问题,我认为您应该将@ManyToOne Master移动到详细ID(删除insertable = false选项)。
您还应该将选项mappedBy =“detailsPrimaryKey.master”添加到@OneToMany注释中,如果您希望自动保存子项,也可以添加级联。
(看http://beavercreekconsulting.com/blog/2008/10/hibernate-annotations-for-a-one-to-many-mapping/你会看到代码解决与你的问题非常相似的代码)
答案 1 :(得分:0)
我有同样的问题。起初我想使用@PrimaryKeyJoinColumn,但不是所有Details主键列都是外键。所以我将使用@JoinColumn。但正如您所说,JPA实现没有选择在写入时将自动生成的主键分配给数据库,而是查阅了SEQUENCE表。我认为这会浪费密钥,并且可能导致并发/同步问题,从数据库中获取可能甚至不会最终提交给DB的实体的ID。