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

在 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)
172522 次浏览

根据这个 那么线头,解决方案是使用非基元包装类型; 例如,使用 Integer而不是 int

A null value cannot be assigned to a primitive type, like int, long, boolean, etc. If the database column that corresponds to the field in your object can be null, then your field should be a wrapper class, like Integer, Long, Boolean, etc.

危险在于,如果数据库中没有空值,那么您的代码将运行良好,但是一旦插入空值,代码就会失败。

你总是可以从 getter 返回基元类型。例如:

  private Integer num;


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


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

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

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

基元类型不能为空。因此,解决方案是在 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;
}

reference http://en.wikipedia.org/wiki/Primitive_wrapper_class to find wrapper class of a primivite type.

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

private Integer num;


public Integer getNum()...


public void setNum(Integer num)...

@ Dinh Nhat,setter 方法看起来不对,因为你把一个基元类型放在那里,它应该是:

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

确保数据库 MyAttribute字段包含 null 而不是0。

要么通过 NOT NULL完全避免数据库中的 null,要么通过 @Column(nullable = false)完全避免 Hibernate 实体中的 null,要么使用 Long包装器代替 long原语。

基元不是 Object,因此不能将 null赋给它。

我会用一个例子来帮助你理解。假设您有一个关系表(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;
}


}

Lets assume table already had entries. Now if somebody asks you add another column of "AGE" (int)

Altertable STUDENT ADD AGE int NULL

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

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

或者

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

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

将参数类型从原语更改为 Object,并在 setter 中执行 null 检查

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

有两条路

  • 确保数据库列不允许 null
  • 基元类型变量(如 private int var;)的用户包装类可以初始化为 private Integer var;

不要在 实体类中使用原语,而是使用它们各自的包装器。这将解决这个问题。

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

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

换衣服

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