繁体   English   中英

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

[英]How to generate id based on two foreign keys in JPA / Hibernate?

关于JPA中的实体声明,我有一个简单的问题。 我有一个带有2个外键的实体,这些外键不为null,并形成uniqueConstraint。 首先,我正在考虑一个由两个外键组成的复合键,但是我听说这是一个遗留设计,而不是推荐的设计新表的方式。

因此,我很感兴趣Hibernate / JPA是否可以基于两个外键自动生成id。 假设我有以下实体:

@Entity
public class Foo {
  @ManyToOne
  private Bar bar;
  private int i;
}

(我省略了不是null和uniqueConstraint标记,以使代码更具可读性)

我知道我可以简单地添加一个带有GeneratedValue的id字段,并让我的数据库生成密钥(在我的示例中为MySQL,使用auto_increment),但这对我来说似乎效率不高,因为它涉及查询数据库并要求其生成唯一ID值。

有没有一种方法可以基于“ Bar”类的ID和整数“ i”的值来生成非复合ID(即int或long类型),因为这两个值已经形成了独特的约束?

您可能需要查看“ 带有Hibernate的Java持久性 ”的第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,可更新= false的原因。

这很棘手,但是如果您真的想这样做,那就有可能。

祝你好运,J。

我认为“效率低下”如此之小,在99.99%的情况下可以忽略不计。

对于支持自动增量列的数据库,没有额外的往返请求。 对于不支持自动递增列的数据库(例如Oracle),Hibernate进行了一些优化,以减少ID生成的数据库访问(例如,获取序列值,乘以50,并将结果中的下50个值用作新实体的ID) )

我认为您应该在这里重新考虑您的设计; 拥有一个组合键,或者更好地使用一个ID可能更有意义。

从外键中生成主键值的原理可能适得其反。 这是因为不打算修改主键-如果其中一个外键值发生更改怎么办? 是否应该重新生成主键值? 并且是否应该修改其他表中的列引用? 无论如何,JPA都要求不要更改主键,因此最好不要使用自然键或代理键。

编写生成器的工作最好用于确保模型正确。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM