为什么我在Grails中使用HibernateCriteriaBuilder的时候得到一个“空值赋给原始typessetter的属性”错误信息
在我的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)
根据这个SO线程 ,解决scheme是使用非原始包装types; 例如, Integer
而不是int
。
一个null值不能被分配给一个原始types,比如int,long,boolean等等。如果与你的对象中的字段对应的数据库列可以为null,那么你的字段应该是一个包装类,比如Integer,Long,布尔等
危险在于如果数据库中没有空值,则代码将正常运行,但一旦插入空值就会失败。
而且你总是可以从getter中返回原始types。 例如:
private Integer num; public void setNum(Integer i) { this.num = i; } public int getNum() { return this.num; }
但是在大多数情况下,你会想要返回包装类。
所以要么设置你的数据库列不允许空值,要么使用包装类。
原始types不能为空。 所以解决方法是在你的tableName.java文件中用原始包装类replace原始types。 如:
@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_classfind一个primivitetypes的包装类。;
使用Integer作为types,并相应地提供setter / getter。
private Integer num; public Integer getNum()... public void setNum(Integer num)...
@Dinh Nhat,你的setter方法看起来是错误的,因为你再次把一个原始types,它应该是:
public void setClient_os_id(Integer clientOsId) { client_os_id = clientOsId; }
我会尽量让你理解一个例子的帮助。 假设你有一个关系表(STUDENT),有两列,ID(int)和NAME(String)。 现在作为ORM,你可能会像下面这样创build一个实体类:
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; } }
让我们假设表已经有条目。 现在如果有人问你添加另一列“年龄”(int)
ALTER TABLE STUDENT ADD AGE int NULL
您必须将默认值设置为NULL才能在预填表中添加另一列。 这使您可以在课程中添加另一个字段。 现在,问题出现在你将使用基本数据types还是非基本包装数据types来声明该字段。
@Column(name = "AGE") private int age;
要么
@Column(name = "AGE") private INTEGER age;
您必须将该字段声明为非原始包装数据types,因为容器将尝试将表映射到实体。 因此,如果您不会将字段声明为包装器,并且最终会抛出“空值已分配给基本types设置器的属性”exception,则无法映射NULL值(默认值)。
要么通过NOT NULL
在Hibernate实体中通过NOT NULL
完全避免null
,要么通过@Column(nullable = false)
完全避免在NOT NULL
,或者使用Long
包装器而不是long
原语。
原语不是一个对象,因此你不能给它赋值null
。
将参数types从基元改为对象,并在设置器中进行空检查。 看下面的例子
public void setPhoneNumber(Long phoneNumber) { if (phoneNumber != null) this.phoneNumber = phoneNumber; else this.extension = 0l; }
确保你的数据库myAttribute字段包含null而不是零。