为什么在Grails中使用HibernateCriteriaBuilder时,“Null值被分配给基本类型setter的属性”错误消息

时间:2010-07-01 01:33:12

标签: grails gorm

在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)

12 个答案:

答案 0 :(得分:130)

根据这个SO thread,解决方案是使用非原始包装类型;例如,Integer而不是int

答案 1 :(得分:40)

无法将null值分配给基本类型,如int,long,boolean等。如果对应于对象中字段的数据库列可以为null,那么您的字段应该是一个包装类,如Integer ,长,布尔等

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

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

  private Integer num;

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

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

但在大多数情况下,你会想要返回包装类。

因此,要么将数据库列设置为不允许空值,要么使用包装类。

答案 2 :(得分:12)

基本类型不能为空。所以解决方案是在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以查找primivite类型的包装类。

答案 3 :(得分:6)

我会试着通过一个例子来帮助你理解。假设您有一个关系表(STUDENT),它有两列,ID(int)和NAME(String)。现在作为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”(int)

  

ALTER TABLE STUDENT ADD AGE int NULL

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

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

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

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

答案 4 :(得分:5)

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

private Integer num;

public Integer getNum()...

public void setNum(Integer num)...

答案 5 :(得分:3)

@Column(name ="LEAD_ID")
private int leadId; 

更改为

@Column(name ="LEAD_ID")
private Integer leadId; 

答案 6 :(得分:2)

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

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

答案 7 :(得分:2)

通过null完全避免数据库中的NOT NULL,并通过@Column(nullable = false)完全避免使用Hibernate实体,或使用Long包装器而不是long原语。

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

答案 8 :(得分:2)

将参数类型从基元更改为Object,并在设置器中放置空检查。见下面的例子

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

答案 9 :(得分:1)

确保您的数据库 myAttribute 字段包含null而不是零。

答案 10 :(得分:1)

有两种方法

  • 确保不允许db列null
  • 诸如private int var;之类的原始类型变量的用户包装程序类可以初始化为private Integer var;

答案 11 :(得分:0)

请勿在您的实体类中使用基元,而应使用它们各自的包装器。这样可以解决这个问题。

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