我从JPA2开始,到目前为止感觉相当舒适。但是,当使用默认值为NON NULL数据库字段保留具有空属性值的实体时,我遇到了问题。
我希望能够将实体属性保留为null,并让数据库插入默认值。
我目前的设置是使用PostgreSQL的openJPA。
我有这个VERSION数据库表(Vorgabewert =默认值):
Spalte | Typ | Attribute
----------------+-----------------------------+----------------------------
status_ | smallint | not null Vorgabewert 0
time_ | timestamp without time zone | not null
system_time | timestamp without time zone | not null Vorgabewert now()
version | character varying(20) | not null
activationtime | timestamp without time zone |
importtime | timestamp without time zone |
我有一个实体(Java DTO),它通过xml配置映射数据库字段('status'除外)。
我希望我可以在没有设置system_time
的情况下插入实体,并期望数据库将当前时间填充为默认值。
JPA构造以下SQL-Query:
INSERT INTO public.version (version, activationtime, importtime, system_time, time_) VALUES (?, ?, ?, ?, ?) [params=?, ?, ?, ?, ?]
和Postgres做出反应:
FEHLER: NULL-Wert in Spalte »system_time« verletzt Not-Null-Constraint
(对不起德语,但是这条消息意味着'system_time'上的Not-Null-Constraint违规行为。)
那我该怎么办?这是JPA还是数据库问题。 我是否可以将JPA配置为从INSERT SQL语句中排除null属性。
我希望能够在我的实体中设置'system_time'或让它为'null'并让数据库设置默认值。
欢迎任何帮助!
Regads 克劳斯
答案 0 :(得分:20)
使用注释
@Column(insertable = false)
将阻止在sql中生成该值。
答案 1 :(得分:17)
我不会将数据库中的默认值与JPA结合使用。您必须在插入后读取实体,否则您将在实体状态和db状态之间不匹配。
在此处选择实用方法并初始化java中的所有值。从未听说过告诉JPA / Hibernate在插入/更新中遗漏空值的方法。
答案 2 :(得分:6)
在注释 @Column 中,将属性 可插入 设为false,如下所示:
`@Column(name="system_time", insertable = false)`
或者,如果你需要检查值是否为NULL,那么在表上进行INSERT INSFORE之前。
答案 3 :(得分:2)
来自文档: columnDefinition:为列生成DDL时使用的SQL片段。
通过使用columnDefinition,您可以根据需要指定约束。
@Column(name =“COLUMN_NAME”,columnDefinition =“DATE DEFAULT CURRENT_DATE”,table =“TABLE_NAME”)
否则你可以尝试初始化实体本身的字段以摆脱这个。
@Column(name = "somedate", nullable = false)
private Date someDate = new Date();
因此,默认情况下,如果您未设置当前日期,则会插入当前日期。
答案 4 :(得分:1)
我找到了一个简单的解决方案: 在pojo中定义默认值。
@Column(name="system_time")
private Date systemTime = new Date();
答案 5 :(得分:1)
对于那些将 Spring Framework 与 JPA 结合使用的人,请查看本文的第 4 部分以获得优雅的解决方案。 BAELDUNG 的所有功劳
https://www.baeldung.com/database-auditing-jpa
注意:粘贴文章摘录以保留内容
Spring Data JPA 是一个框架,它通过在 JPA 提供程序的顶部添加一个额外的抽象层来扩展 JPA。该层允许通过扩展 Spring JPA 存储库接口来支持创建 JPA 存储库。
出于我们的目的,您可以扩展 CrudRepository
4.1.启用 JPA 审计 首先,我们希望通过注释配置启用审计。为此,只需在 @Configuration 类上添加 @EnableJpaAuditing:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories
@EnableJpaAuditing
public class PersistenceConfig { ... }
4.2.添加 Spring 的实体回调侦听器 正如我们已经知道的,JPA 提供了 @EntityListeners 注释来指定回调侦听器类。 Spring Data 提供了自己的 JPA 实体侦听器类:AuditingEntityListener。因此,让我们为 Bar 实体指定侦听器:
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Bar { ... }
现在,监听器将在持久化和更新 Bar 实体时捕获审计信息。
4.3.跟踪创建日期和上次修改日期 接下来,我们将添加两个新属性,用于将创建日期和上次修改日期存储到我们的 Bar 实体中。属性由 @CreatedDate 和 @LastModifiedDate 注释相应地注释,并且它们的值是自动设置的:
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Bar {
//...
@Column(name = "created_date", nullable = false, updatable = false)
@CreatedDate
private long createdDate;
@Column(name = "modified_date")
@LastModifiedDate
private long modifiedDate;
//...
}
通常,您会将属性移动到一个基类(由@MappedSuperClass 注释),该基类将被所有审计实体扩展。在我们的示例中,为了简单起见,我们将它们直接添加到 Bar 中。
4.4.使用 Spring Security 审计更改的作者 如果您的应用使用 Spring Security,您不仅可以跟踪更改的时间,还可以跟踪更改的人员:
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Bar {
//...
@Column(name = "created_by")
@CreatedBy
private String createdBy;
@Column(name = "modified_by")
@LastModifiedBy
private String modifiedBy;
//...
}
用@CreatedBy 和@LastModifiedBy 注释的列填充了创建或最后修改实体的主体的名称。该信息是从 SecurityContext 的 Authentication 实例中提取的。如果要自定义设置为注释字段的值,可以实现 AuditorAware 接口:
public class AuditorAwareImpl implements AuditorAware<String> {
@Override
public String getCurrentAuditor() {
// your custom logic
}
}
为了配置应用程序以使用 AuditorAwareImpl 来查找当前主体,声明一个使用 AuditorAwareImpl 实例初始化的 AuditorAware 类型的 bean,并将 bean 的名称指定为 @EnableJpaAuditing 中的 auditAwareRef 参数值:
@EnableJpaAuditing(auditorAwareRef="auditorProvider")
public class PersistenceConfig {
//...
@Bean
AuditorAware<String> auditorProvider() {
return new AuditorAwareImpl();
}
//...
}
答案 6 :(得分:0)
我使用它(针对Oracle数据库):
@Temporal(TemporalType.TIMESTAMP)
@Column(name="CREATION_TIME",
columnDefinition="TIMESTAMP DEFAULT SYSTIMESTAMP",
nullable=false,
insertable=false,
updatable=false)
private Date creationTime;
答案 7 :(得分:0)
你可以通过在@column注释中添加nullable = false来避免null属性。像这样
@Column(name = "muColumn", nullable = false)
答案 8 :(得分:0)
要在休眠插入sql stmt中排除空属性值,请使用属性 dynamic-insert = true 。
1. @ org.hibernate.annotations.Entity(dynamicInsert = true)将其添加到类中 2.在xml映射中,在类标记中使用dynamic-insert = true属性。
答案 9 :(得分:-1)
只需从INSERT语句中的列中省略system_time。
答案 10 :(得分:-1)
我不知道在JPA中如何做到这一点。
但是您可以向数据库添加一个触发器,该触发器捕获尝试将NULL插入到相关列中,并重写插入以插入默认值?实际上,您将默认生成行为完全转移到数据库中,而不是在JPA和数据库之间拆分。
但是,正如伯特在答案中指出的那样,这会使对象和数据库不一致,这几乎肯定是一个糟糕的想法。
答案 11 :(得分:-1)
你可以这样使用:
@JoinColumn(name = "team_id", nullable = false)
使用这种方式, JPA 会检查NULL
值。