hibernate 休眠工具(hbm2java):缺少列默认值[重复]

fzsnzjdm  于 2023-02-04  发布在  Java
关注(0)|答案(2)|浏览(112)
    • 此问题在此处已有答案**:

(18个答案)
9天前关闭。
我正在使用hbm2java(它是Hibernate Tools的一部分)将数据库反向工程为JPA实体类。
我通过./mvnw clean generate-sources运行该工具,生成实体类并保存到target/generated-sources
UserAccount数据库表中,Created列的定义如下。请注意默认值:

Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,

当hbm2java对该列进行反向工程时,不包括缺省值:

...
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, length = 29)
public Timestamp getCreated() {
    return this.created;
}

public void setCreated(Timestamp created) {
    this.created = created;
}
...

因此,在尝试将UserAccount实体保存到数据库时会引发DataIntegrityViolationException
数据完整性违规异常:非空属性引用空值或 transient 值:com.example.UserAccount.created
真的希望有一种方法可以解决这个问题,因为我有相当多的数据库列有默认值,最复杂的是:

DEFAULT 'User' + CAST(NEXT VALUE FOR SeqUserAccountUsername as VARCHAR(19))

...只生成字符串,如User13。
我还在学习SpringBoot和Hibernate,可能需要一些关于解决这个问题的最佳方法的建议。
我目前的研究:

  • same question早在2007年就在Hibernate论坛上被要求使用,但没有提供解决方案。
  • This documentation谈到使用"default-value"属性来设置"字段的默认初始化值",这是正确的方法吗?
tvokkenx

tvokkenx1#

我 * 相信 * 下面的Map应该可以在所有最近的Hibernate版本中工作:

@Generated(INSERT)
@ColumnDefault("CURRENT_TIMESTAMP")
@Column(nullable = false)
public Timestamp getCreated() {
    return this.created;
}

如果不管用,告诉我。
(It当然,逆向工程工具对默认值一无所知。)

b0zn9rqh

b0zn9rqh2#

首先,你需要找一个能够解释数据库工作原理的人。问题是像TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL这样的SQL列定义意味着:

  • 永远不要选择null
  • 你不能插入/设置空
  • 你可以插入/设置非空
  • 您可以在DML语句中省略column或指定DEFAULT,在这种情况下DB根据默认表达式生成值(在您的情况下为CURRENT_TIMESTAMP

要在Hibernate中获得完全相同的功能/能力,最简单的方法是使用JPA Callbacks,smth。例如:

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, /* updatable = false, */ length = 29)
public Timestamp getCreated() {
    return this.created;
}

@PrePersist
protected void onPrePersist() {
     if (this.created == null) {
         this.created = Timestamp.from(Instant.now());
     }
}

它允许你指定任意创建的时间戳,并且只有当它是nullHibernate时才会使用当前时间--这正是DB允许你做的。
其他选项做类似的事情,但不一样,但其中一些可能适合你。

  1. @CreationTimestamp
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, length = 29)
public Timestamp getCreated() {
    return this.created;
}

它忽略this.created的值,并将Java端计算的当前时间插入DB。

  1. @Generated(GenerationTime.INSERT)
@Generated(GenerationTime.INSERT)
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, length = 29)
public Timestamp getCreated() {
    return this.created;
}

它忽略了this.created的值,并将值的生成委托给DB,基本上它省略了INSERT语句中的相应列(嗯......"generate"在这里不是正确的定义)。
如果您选择使用@CreationTimestamp@Generated(GenerationTime.INSERT),请删除相应setter void setCreated(Timestamp created),以避免混淆created字段的可变性。

相关问题