Grails,GORM,关系。可选的子记录

时间:2015-04-17 20:54:18

标签: grails gorm

例如,我是父类Cafee:

class Cafee {    
    String name
    static hasMany = [
         admin: Person
    ]
}

和一个子类人员:

class Person {    
    String name
    static belongsTo = [cafee: Cafee]
}

我使用以下方式为Cafee做了一些记录:

def user = new Person(name: "Andrew")
def a = new Cafee(name: "Tarelka")
             .addToAdmin(user)
             .save()

将子项添加到父项可以正常工作,但是当我尝试单独创建Person-instance时,例如:

def visitor = new Person(username: 'testerUser', password:'password', firstName:'Иван', lastName:'Иванов', email:'ivanov@gmail.com', isAdminCafee: false)
         visitor.save(flush:true)

我收到错误:

ERROR context.GrailsContextLoaderListener  - Error initializing the application: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person
Message: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person

如何解决?

1 个答案:

答案 0 :(得分:2)

这里有两件事情并不完全明显。一种是这种形式的belongsTo

static belongsTo = [cafee: Cafee]

相比,

是双向的

static belongsTo = [Cafee]

是不定向的;在两种变体中,Cafee可以通过其Person集合访问其关联的admin实例,但使用第二种语法,Person没有直接的方法可以知道Cafee hasMany它与。

相关联

像你一样声明Set会在班级中创建PersonhasMany,其名称是您在admin地图中使用的密钥,在此情况1}};好像你已经添加了

Set<Person> admin

但你不应该因为它是多余的 - AST转换将该属性添加到字节码。

同样,在声明时

static belongsTo = [cafee: Cafee]

将类型Cafee的字段cafee添加到类中。就好像你添加了

Cafee cafee

但请再次注意,请不要手动添加,只要注意它们就在那里。

所以问题是默认情况下持久属性不是null,除非你用nullable: true覆盖,所以如果你打印出Person个实例的错误,你会看到至少有一个抱怨不可为空的cafee属性为null。这与addToAdmin一起使用,因为该方法做了很多。如果将set实例化为新的Set接口实现(可能只是HashSet),如果它为null(这应该只在域类实例是新的时才会发生;持久集永远不会为null,只是清空或包含项目),然后将Person添加到集合中,最后如果关系是双向的,则会将Person上的反向引用设置为拥有Cafee

所以你所缺少的是手动设置Cafee,作为地图构造函数的一部分

user = new Person(cafee: a, username: 'testerUser', ...)
工作流程中的

或更高版本(但在验证或保存之前)

user = new Person(username: 'testerUser', ...)
...
user.cafee = a
...
user.save()