在Grails中使用HibernateCriteriaBuilder时,为什么会收到“将Null值分配给原始类型设置器的属性”错误消息


100

在grails域对象中使用原始属性时,出现以下错误:

Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
 org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
at grails.orm.HibernateCriteriaBuilder.invokeMethod(HibernateCriteriaBuilder.java:1077)

不要搞乱您的数据输入,也不必使用非原始包装器。我错过了输入一些值的方法,并设法通过将其添加到数据库中来解决此错误。
2013年

Answers:



46

无法将null值分配给基本类型,例如int,long,boolean等。如果与对象中的字段相对应的数据库列可以为null,则您的字段应为包装类,例如Integer,Long,布尔值等

危险是,如果数据库中没有空值,则代码将正常运行,但是一旦插入空值,代码将失败。

而且,您始终可以从getter返回原始类型。例如:

  private Integer num;

  public void setNum(Integer i) {
    this.num = i;
  }

  public int getNum() {
    return this.num;
  }

但是在大多数情况下,您将需要返回包装器类。

因此,要么将DB列设置为不允许为空,要么使用包装器类。


13

基本类型不能为null。因此,解决方案是用tableName.java文件中的原始包装器类替换原始类型。如:

@Column(nullable=true, name="client_os_id")
private Integer client_os_id;

public int getClient_os_id() {
    return client_os_id;
}

public void setClient_os_id(int clientOsId) {
    client_os_id = clientOsId;
}

请参考http://en.wikipedia.org/wiki/Primitive_wrapper_class来查找原始类型的包装器类。


8

我将通过一个示例来使您理解。假设您有一个包含两列以及ID(int)和NAME(String)的关系表(STUDENT)。现在,作为ORM,您将使实体类如下所示:-

package com.kashyap.default;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author vaibhav.kashyap
 *
 */
@Entity
@Table(name = "STUDENT")
public class Student implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -1354919370115428781L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "NAME")
    private String name;

    public Student(){

    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

假设表已经有条目。现在,如果有人要求您添加另一列“ AGE”(整数)

ALTER TABLE STUDENT ADD AGE int NULL

您必须将默认值设置为NULL才能在预填充表中添加另一列。这使您可以在类中添加另一个字段。现在出现的问题是您将使用原始数据类型还是非原始包装器数据类型来声明字段。

@Column(name = "AGE")
private int age;

要么

@Column(name = "AGE")
private INTEGER age;

您必须将字段声明为非原始包装数据类型,因为容器会尝试将表与实体映射。因此,如果您不将字段声明为包装器,则它将无法映射NULL值(默认),并最终抛出“将Null值分配给原始类型setter的属性”异常。


6

使用Integer作为类型,并相应地提供setter / getter。

private Integer num;

public Integer getNum()...

public void setNum(Integer num)...

4

不要在Entity类中使用基元,而应使用它们各自的包装器。这将解决此问题。

在您的Entity类之外,您可以对其余代码流使用!= null验证。


3

相应地,完全避免null在DB中通过NOT NULL和在Hibernate实体中通过@Column(nullable = false)使用Long包装器来代替long原始方法。

基元不是对象,因此您无法为其分配对象null


3

有两种方法

  • 确保不允许使用db列 null
  • 像这样的原始类型变量的User Wrapper类private int var;可以初始化为private Integer var;

2

@Dinh Nhat,您的setter方法看起来不对,因为您再次在其中放置了原始类型,它应该是:

public void setClient_os_id(Integer clientOsId) {
client_os_id = clientOsId;
}

2

将参数类型从原始类型更改为Object,然后在setter中进行空检查。见下面的例子

public void setPhoneNumber(Long phoneNumber) {
    if (phoneNumber != null)
        this.phoneNumber = phoneNumber;
    else
        this.extension = 0l;
}


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.