我有一个关于JPA中实体声明的简单问题。 我有一个带有2个外键的实体,它们不是null并且形成uniqueConstraint。首先,我在考虑一个由两个外键组成的复合键,但我听说这是一个遗留设计,而不是设计新表的推荐方法。
所以我感兴趣的是Hibernate / JPA能否根据两个外键自动生成id。假设我有以下实体:
@Entity
public class Foo {
@ManyToOne
private Bar bar;
private int i;
}
(我省略了not null和uniqueConstraint标签,以使代码更具可读性)
我知道我可以简单地使用GeneratedValue添加一个id字段,并让我的数据库生成密钥(在我的示例MySQL中使用auto_increment),但这对我来说似乎效率低,因为它涉及查询数据库并要求它生成唯一的id值。
有没有一种生成id的方法,它不是复合的(即int或long类型),基于“Bar”类的id和整数“i”的值,因为它是那两个值已形成一个独特的约束?
答案 0 :(得分:5)
您可能需要查看“Java Persistence with Hibernate”的第7章。
您可以将复合键建模为 Embeddable :
import javax.persistence.*;
import java.io.Serializable;
@Entity
public class Foo {
@Embeddable
public static class Id implements Serializable {
@Column(name = "bar_id_col")
private Long barId;
@Column(name = "i_col")
private int i;
public Id() {
}
public Id(Long barId, int i) {
this.barId = barId;
this.i = i;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Id)) {
return false;
}
final Id id = (Id) o;
if (i != id.i) {
return false;
}
if (barId != null ? !barId.equals(id.barId) : id.barId != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = barId != null ? barId.hashCode() : 0;
result = 31 * result + i;
return result;
}
}
@EmbeddedId
private Id id = new Id();
@ManyToOne
@JoinColumn(name = "bar_id_col", insertable = false, updatable = false)
private Bar bar;
private int i;
public Foo() {
}
public Foo(Bar bar, int i) {
// set fields
this.Bar = bar;
this.i=i;
// set identifier values
this.id.barId = bar.getId();
this.id.i = i;
}
}
这里我假设Bar看起来像:
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Bar {
@Id
Long id;
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
}
请注意,这会将 bar_id_col 映射两次。这是第二个引用中 insertable = false,updatable = false 的原因。
这很棘手,但如果你真的想这样做,那就有可能。
祝你好运, 学家答案 1 :(得分:1)
我认为'效率低下'非常小,99.99%的情况下可以忽略它。
对于支持自动增量列的数据库,要求它生成ID没有额外的往返行程。对于不支持自动增量列的数据库(例如Oracle),Hibernate进行了一些优化以减少ID生成的数据库访问(例如,获取序列值,乘以50并使用结果中的后50个值作为新实体的ID )
答案 2 :(得分:1)
我认为你应该重新考虑你的设计;拥有一个复合键可能更有意义,或者更好的是Id。
从外键生成主键值的基本原理可能适得其反。这是因为主键不是要修改的 - 如果其中一个外键值发生变化会怎样?是否应重新生成主键值?并且应该修改其他表中的列引用吗?在任何情况下,JPA都要求不更改主键,因此最好使用自然键或代理键。
编写生成器的努力最好用于确保模型正确。