如何在JPA / Hibernate中基于两个外键生成id?

我在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”的值,因为它们已经形成了这两个值独特约束?     
已邀请:
您可能需要查看“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的原因。 这很棘手,但如果你真的想这样做,那就有可能。 祝好运, J.     
我认为“无效率”是如此微不足道,在99.99%的情况下,它可以被忽略。 对于支持自动增量列的数据库,要求它生成ID没有额外的往返行程。对于不支持自动增量列的数据库(例如Oracle),Hibernate进行了一些优化以减少ID生成的数据库访问(例如,获取序列值,乘以50并使用结果中的后50个值作为新实体的ID )     
我想你应该在这里重新考虑你的设计;拥有复合键或者更好的Id可能更有意义。 从外键生成主键值的基本原理可能适得其反。这是因为主键不是要修改的 - 如果其中一个外键值发生变化会怎样?是否应重新生成主键值?并且应该修改其他表中的列引用吗?在任何情况下,JPA都要求不更改主键,因此最好使用自然键或代理键。 编写生成器的努力最好用于确保模型正确。     

要回复问题请先登录注册