我有一个具有唯一约束的列的表。我希望约束检查推迟到提交时间。
如果我像这样使用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
)

然后一切按预期进行。
如果我将其定义为这样休眠:
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创建表时,不会为名称的唯一约束指定初始延迟选项(正如预期的那样,因为我不知道如何请求它)
当我运行应用程序时,坏事情就会发生。
特别是允许用户在两个仪器之间交换名称。如果他试图在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属性?
我不是在找工作。在安装/设置过程中,我有一个额外的步骤来应用约束。我所希望的是一种消除额外步骤的方法。

最佳答案

不幸的是,Hibernate不支持延迟约束。
https://hibernate.atlassian.net/browse/HHH-2248
您可以尝试使用entityManager.flush()方法,假设您有名称为inst1和inst2的仪器:

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");

或者,可以从DB获取实体,从DB中删除它们,执行flush并持久化更新的实体。这样你就不用编第三个名字了。
不确定这些解决方案的性能效果,您必须自己弄清楚。

关于postgresql - 可以使用Hibernate注释定义INITIALLY DEFERRED约束吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47317706/

10-16 11:41