本文介绍了初始化DEFERRED约束可以使用Hibernate注释来定义吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

 
id bigint NOT NULL,
名称字符变化(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)
公共类仪器实现可版本化,可序列化{
private static final long serialVersionUID = 1L;

public static final String NAME_PROPERTY =name;

@版本
private int version;

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

@Column(name =name,unique = true,nullable = false)
私有字符串名称;
$ b $ public Instrument(){
//构造函数使Hibernate开心
}

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

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

$ b @Override
public String toString(){
returnInstrument [id =+ id +,name =+ name +] ;


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

当我运行应用程序时,发生了不好的事情。



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

  org.postgresql.util.PSQLException:错误:重复键值违反唯一约束instrument_name_key
详细信息:键(名称)=(inst1)已经存在。

所以问题是:是否有一个Hibernate注释可以用来指定 INITIALLY DEFERRED 列上的约束属性?



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

解决方案

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



您可以尝试使用entityManager.flush()方法进行游戏,假设您的Instruments名称为 inst1 inst2

  Instrument inst1 = entityManager.find(Instrument.class,1); 
//将第一个乐器的名称更改为随机一个
inst1.setName(inst3);
entityManager.flush();
Instrument inst2 = entityManager.find(Instrument.class,2);
inst2.setName(inst1);
entityManager.flush();
inst1.setName(inst2);

或者,您可以从数据库获取实体,从数据库中删除它们,执行刷新和持久更新的实体。这种方式你不必补足第三个名字。



不知道这些解决方案的性能影响,你必须弄清楚你自己。 b $ b

I have a table with a column that has a UNIQUE constraint. I want the constraint checking to be deferred to commit time.

If I create it using Postgres SQL like this (many columns omitted):

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
)

Then everything works as expected.

If I define it to Hibernate like this:

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 + "]";
    }
}

And use hibernate.hbm2ddl create to create the table, the INITIALLY DEFERRED option is not specified for the name's UNIQUE constraint (as expected because I don't know how to ask for it.)

When I run the app bad things happen.

In particular the user is allowed to swap names between two instruments. If he tries to swap the names between inst1 and inst2 it throws an exception:

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

So the question is: Is there an Hibernate annotation that can be used to specify the INITIALLY DEFERRED property of a constraint on a column?

PS: I'm not looking for a work-around. I have an extra step in the install/setup process that applies the constraint. What I'm hoping for is a way to eliminate that extra step.

解决方案

Unfortunately, Hibernate does not have support for deferred constraints.https://hibernate.atlassian.net/browse/HHH-2248

You could try playing with entityManager.flush() method, let's say you have Instruments with names inst1 and 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");

Alternatively you could get the entities from DB, delete them from DB, perform flush and persist updated entities. This way you don't have to make up the third name.

Not sure about performance effect of those solutions, you have to figure out yourself.

这篇关于初始化DEFERRED约束可以使用Hibernate注释来定义吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 03:28