避免通过JPA向数据库表插入'null'值

时间:2010-12-22 11:19:15

标签: java postgresql orm jpa jpa-2.0

我从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   克劳斯

12 个答案:

答案 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,通用 CRUD 操作的接口。一旦您创建了存储库并将其注入到另一个组件中,Spring Data 就会自动提供实现,您就可以添加审计功能了。

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)

how to avoid the null property in insert or update

答案 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值。