【问题标题】:Can an INITIALLY DEFERRED constraint be defined using a Hibernate annotation?可以使用 Hibernate 注释定义 INITIALLY DEFERRED 约束吗?
【发布时间】:2017-11-15 21:38:17
【问题描述】:

我有一个表,其中有一列具有 UNIQUE 约束。我希望将约束检查推迟到提交时间。

如果我像这样使用 Postgres SQL 创建它(省略了许多列):

CREATE TABLE instrument
(
  id bigint NOT NULL,
  name character varying(255) NOT NULL,
  CONSTRAINT instrument_pkey PRIMARY KEY (id),
  CONSTRAINT instrument_name_key UNIQUE (name)
     DEFERRABLE INITIALLY DEFERRED
)

然后一切都按预期进行。

如果我像这样将其定义为 Hibernate:

import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.ForeignKey;

@Entity
@Table(name="instrument")
public class Instrument implements Versionable, Serializable {
    private static final long serialVersionUID = 1L;

    public static final String NAME_PROPERTY = "name";

    @Version
    private int version;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GEN")
    private Long id;

    @Column(name="name", unique=true, nullable=false)
    private String name;

    public Instrument() {
       // null constructor to make Hibernate happy
    }

    public Instrument(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getName());
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Instrument) {
            Instrument other = (Instrument)obj;
            return Objects.equal(getName(), other.getName());
        }
        return false;
    }

    @Override
    public String toString() {
        return "Instrument [id=" + id + ", name=" + name + "]";
    }
}

并使用hibernate.hbm2ddl create创建表,名称的UNIQUE约束没有指定INITIALLY DEFERRED选项(正如预期的那样,因为我不知道如何要求它。)

当我运行应用程序时,会发生坏事。

特别是允许用户在两​​个仪器之间交换名称。如果他尝试在 inst1 和 inst2 之间交换名称,则会引发异常:

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "instrument_name_key"
  Detail: Key (name)=(inst1) already exists.

那么问题来了:是否有Hibernate注解可以用来指定列约束的INITIALLY DEFERRED属性?

PS:我不是在寻找解决方法。我在应用约束的安装/设置过程中有一个额外的步骤。我所希望的是一种消除额外步骤的方法。

【问题讨论】:

    标签: postgresql hibernate hibernate-annotations


    【解决方案1】:

    不幸的是,Hibernate 不支持延迟约束。 https://hibernate.atlassian.net/browse/HHH-2248

    您可以尝试使用 entityManager.flush() 方法,假设您有名称为 inst1inst2 的 Instruments:

    Instrument inst1 = entityManager.find(Instrument.class, 1);
    // change name of first Instrument to some random one
    inst1.setName("inst3");
    entityManager.flush();
    Instrument inst2 = entityManager.find(Instrument.class, 2);
    inst2.setName("inst1");
    entityManager.flush();
    inst1.setName("inst2");
    

    或者,您可以从数据库中获取实体,从数据库中删除它们,执行刷新和持久化更新的实体。这样你就不用编第三个名字了。

    不确定这些解决方案的性能效果,您必须自己弄清楚。

    【讨论】:

      【解决方案2】:

      如果您使用 Flyway 或其他数据库版本控制/迁移工具,您只需在定义 Hibernate/JPA 生成的约束的文件之后添加另一个版本的 DDL 文件。这个附加文件会将这些约束重新定义为 DEFERRABLE INITIALLY DEFERRED。

      【讨论】:

        猜你喜欢
        • 2012-04-19
        • 1970-01-01
        • 2018-11-20
        • 1970-01-01
        • 2013-03-03
        • 1970-01-01
        • 2011-04-04
        • 1970-01-01
        • 2013-01-15
        相关资源
        最近更新 更多