我正在使用hbm2java,这是Hibernate工具的一部分,将数据库反向工程为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
:
org.springframework.dao。DataIntegrityViolationException:过的非null的属性引用空值或瞬态值:com.example.UserAccount.created
真的希望有一种方法,因为我有相当多的数据库列与默认值,最复杂的是:
DEFAULT 'User' + CAST(NEXT VALUE FOR SeqUserAccountUsername as VARCHAR(19))
…它只生成一个字符串,如User13.
我还在学习Spring Boot和Hibernate,需要一些建议来解决这个问题。
我目前的研究:
- 同样的问题早在2007年Hibernate论坛上就有人问过,但没有提供解决方案。
- 本文档讨论了如何使用"default-value"属性设置"字段的默认初始化值"。这是正确的方法吗?
我相信下面的映射应该可以在所有最新的Hibernate版本中工作:
@Generated(INSERT)
@ColumnDefault("CURRENT_TIMESTAMP")
@Column(nullable = false)
public Timestamp getCreated() {
return this.created;
}
如果不行,告诉我。
(当然,逆向工程工具不知道任何默认值)
首先,您需要找到能够阐明该数据库如何工作的人。问题是像TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
这样的SQL列定义意味着:
- 你从不选择null
- 不能插入/set null
- 你可以插入/set not null
- 您可以在DML语句中省略列或指定
DEFAULT
,在这种情况下,DB根据默认表达式(在您的情况下是CURRENT_TIMESTAMP
)生成值
使与完全相同的最简单的选项Hibernate
的功能/能力,是使用JPA回调,史密斯。如:
@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());
}
}
允许您指定任意创建的时间戳,并且只有当它是null
Hibernate
时才会使用当前时间-这正是DB允许您做的。
其他选项做类似的事情,但不一样,但其中一些可能适合你。
@CreationTimestamp
:
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED", nullable = false, length = 29)
public Timestamp getCreated() {
return this.created;
}
它忽略this.created
的值,并插入当前时间,在Java端计算,到DB。
@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)
,请删除相应的settervoid setCreated(Timestamp created)
,以避免created
字段的可变性。