Grails gorm的one to many空指针问题

mrice00 2014-03-13

话说最近写的东西都是个人遇到的小问题的笔记,是不是这行干的久了看的多了就不爱写什么理论长文了?

题归正传,其实是个很简单的小问题,就是one to many的时候,如果one一端指明了,many为List类型,则many端会多一个 字段名_idx的字段,值是0,1,2,...如果你只是把many端的外键设置为null,剩下的idx从1,2,3...这样排序,会导致one加载的时候产生一个null,很诡异是吧...话说不知道为什么以前用hibernate的时候从来没有遇到过这个情况。

下面是具体例子。

User类是Many

import groovy.transform.EqualsAndHashCode;

@EqualsAndHashCode
class User {
	String name
	Company company
	static belongsTo = [company: Company]
	
    static constraints = {
		company nullable:true
    }
}

 Comany是One,不过不一定严格关联,User可能属于一个Company,也可能不属于,那就是null。

import groovy.transform.EqualsAndHashCode;

@EqualsAndHashCode
class Company {
	String name
	List<User> users
	static hasMany = [users:User]

	static mapping = {
		users cascade:'none'
	}
}

 现在我插入几条测试数据

new Company(name:'Company1').save()
		new Company(name:'Company2').save()
		
		new User(name:'User1').save()
		new User(name:'User2').save()
		new User(name:'User3').save()
		
		Company company1 = Company.get(1)
		company1.addToUsers(User.get(1))
		company1.addToUsers(User.get(2))

下面我要做的是取消user.get(1)和Company的关联。

于是我在controller里写了如下代码:

def deleteUser(Long id) {
		def u = User.get(id)
		u.company = null
		boolean r = u.save(flush:true)
		if (!r) {
			println "saved ok"
		} else {
			println "not ok"
			println u.errors
		}

	}

 然后发现不好用,company无法被设置为null,不得已只能改为

def deleteUser(Long id) {
		def u = User.get(id)
		u.company = null
		boolean r = u.save(flush:true)
		if (!r) {
			println "saved ok"
		} else {
			println "not ok"
			println u.errors
		}
		int row = User.executeUpdate("update User set company = null where id = ?", [id])
		println "row count:${row}"
	}

结果发现这样是好用了,设置为null了,但是再次加载Company.get(1),然后对users进行循环的时候,发生空指针异常。

仔细看了一下sql发现就是因为List类型会检查users_idx字段,然后按值放到List的index里面,0没有了,只能null。

解决办法是如果需要排序,自己实现Comparable,去掉List<User>这个声明。---当然实际这个问题折腾了我半天时间,因为many那个表字段太多了,根本没发现问题出在哪里,最后做了这么个小例子才看清楚。

不过真的很奇怪为什么之前用了那么久hibernate,一直没遇到过这种场景?

相关推荐