Grails Delete bi-directional one-to-one association
I have two domain classes with bidirectional one to one association:
Domains
class Nose {
String str1
static belongsTo = [face:Face]
}
class Face {
String str1
static hasOne = [nose: Nose]
}
Controllers
class NoseController {
def create() {
nose.properties = params
nose.save(flush: true)
}
def delete() {
def nose = Nose.get(params.id as long)
nose.delete(flush: true)
}
}
class FaceController {
def create() {
def face = new Face()
def nose = Nose.get(params.id as long)
if(!nose){
face.nose = nose
face.properties = params
face.save(flush: true)
nose.face = face
nose.properties = params
nose.save(flush:true)
}else{
face.properties = params
face.save(flush: true)
}
}
def delete() {
def face开发者_StackOverflow = Face.get(params.id as long)
face.delete(flush: true)
}
}
After creating Nose and Face objects, I can't delete and update them. When I want to delete Face I get exception:
org.springframework.dao.DataIntegrityViolationException: Foreign key constraint violation trying to delete teastrelation.Face with id 1 at org.grails.hbase.gorm.DeletePersistentMethod.invoke(DeletePersistentMethod.groovy:66) at org.grails.hbase.gorm.PersistentMethod$invoke.call(Unknown Source) at org.grails.hbase.gorm.PersistentMethod$invoke.call(Unknown Source)
For removing in FaceController I have changed remove action:
def delete() {
def face = Face.get(params.id as long)
def nose = Nose.get(face.nose.id)
face.nose = null
nose.face = null
nose.save(flush:true)
face.save(flush:true)
face.delete(flush: true)
render params.id
}
and only after it I can delete Face object, but it throw the following exception:
ERROR gorm.SavePersistentMethod - Cannot get property 'class' on null object java.lang.NullPointerException: Cannot get property 'class' on null object at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:56) at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:156) at org.codehaus.groovy.runtime.callsite.PojoMetaClassGetPropertySite.callGetProperty(PojoMetaClassGetPropertySite.java:41)
When i want to update Face object, i got the following exception:
ERROR associations.ReferenceTable - Reference table entry not found, row=[79, 78, 69, 84, 79, 79, 78, 69, 95, 79, 78, 69, 84, 79, 79, 78, 69, 95, 68, 79, 77, 65, 73, 78, 50, 95, 0, 0, 0, 0, 0, 0, 0, 1]
ERROR gorm.SavePersistentMethod -Cannot get property 'class' on null object java.lang.NullPointerException: Cannot get property 'class' on null object at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:56) at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:156) at org.codehaus.groovy.runtime.callsite.PojoMetaClassGetPropertySite.callGetProperty(PojoMetaClassGetPropertySite.java:41)
I use grails 1.3.2 and hbase-0.2.4 plugin and I can not use mapping..
What am I doing wrong ?
I have already spent a lot of time on this problem.. please help if anyone can.
I created a simple application to model your issue. In my example, I followed best practices, namely writing a service to manage the objects and some tests. As a note, the create method on your Domain1Controller calls save(flush:true)
3 times (twice on d1 and once on d2), which is probably not good and might be your issue.
Here is what I did
domain class 1:
package com.example
class Owner {
String example;
static constraints = {
friend unique:true
}
static hasOne = [friend: Owned]
}
domain class 2
package com.example
class Owned {
String name;
static constraints = {
}
static belongsTo = [owner: Owner]
}
service to manage those domain classes
package com.example
class OwnerService {
static transactional = true
def saveNewOwnerAndOwned(ownerField, ownedField){
def owner = new Owner(example: ownedField)
def owned = new Owned(name: ownedField)
owner.friend = owned
// since the relationship is bidirectional, need to set up
// the references both ways
owned.owner = owner
owner.save(flush: true)
return owner
}
def deleteOwner(id) {
def toDelete = Owner.get(id)
toDelete.delete(flush:true)
}
def deleteOwnedOfOwner(ownerId) {
def owner = Owner.get(ownerId)
def owned = owner.friend
// must break the relationship
owner.friend = null
owned.delete(flush: true);
}
}
tests to make sure its working
package com.example
class OwnerServiceIntegrationTests extends GroovyTestCase {
def ownerService
def sessionFactory
public void testSave(){
def owner = ownerService.saveNewOwnerAndOwned("im an owner", "im owned");
assertNotNull(owner)
assertNotNull(owner.id)
assertNotNull(owner.friend)
assertNotNull(owner.friend.id)
}
public void testDelete() {
def owner = ownerService.saveNewOwnerAndOwned("im an owner", "im owned");
def id = owner.id
def ownedId = owner.friend.id
ownerService.deleteOwner(id);
// since the integration tests hit an actual db
// clear the session so when i start testing im sure its accurate
def session = sessionFactory.getCurrentSession()
session.clear()
// make sure everything was deleted, i.e. not in db
assertNull(Owner.get(id))
assertNull(Owned.get(ownedId))
}
public void testDeleteOwned() {
def owner = ownerService.saveNewOwnerAndOwned("im an owner", "im owned");
def id = owner.id
ownerService.deleteOwnedOfOwner(id);
def session = sessionFactory.getCurrentSession()
session.clear()
owner = Owner.get(id)
// make sure owner still there but friend is not
assertNotNull(owner)
assertNull(owner.friend)
}
}
精彩评论