2012-08-15 143 views
0

我有一个遗留数据库,我正在使用Grails。错误#1。grails复合密钥更新

它使用化合物密钥。错误#2。

鉴于这些领域类:

Movie { 
    static hasMany = [ roles: Role ] 
} 
Person { 
    static hasMany = [ roles: Role ] 
} 
Role { 
    Movie movie 
    Person person 
    String foo 
} 

我想从一个人移动角色到另一个,就像这样:

Role x = person1.roles[0] 
x.person = person2 
save(flush:true) 

但没有任何反应。完全一样。我在log4j中打开了hibernate的跟踪和调试级别日志记录,并且没有显示更新语句。但是,如果我这样做:

Role x = person1.roles[0] 
x.person = person2 
x.foo = "i can haz update?" 
save(flush:true) 

更新确实发生了FOO,但外键指向人不被修改,如图:

DEBUG hibernate.SQL - update ct_roles set foo=? where movie_id=? and person_id=? 
TRACE sql.BasicBinder - binding parameter [1] as 'i can haz update?' 
TRACE sql.BasicBinder - binding parameter [2] as [BIGINT] - 999 
TRACE sql.BasicBinder - binding parameter [3] as [BIGINT] - 2 

注意PERSON_ID 2属于PERSON2 ,目前它还没有角色,所以更新失败。

因此,短的只是删除旧角色并创建一个新的连接到期望的人,有什么办法解决?

+0

于是,我放弃了对更新的方法,并试图删除旧/插入新的,但是,即使是失败了。 GORM不会让我oldRole.delete(),因为它仍然与oldPerson有关联。我不能oldPerson.removeFromRoles(oldRole); oldRole.delete()因为在那时,oldRole.person == null,并且Hibernate试图从TABLE中删除person_id = null,并且失败。我无法逆转订单,因为“删除行将在保存级联期间被重新创建”。 有血的砖墙,我一直在敲打我的头下的地板上的池,而墙的名字是GORM。 – 2012-08-15 22:22:08

回答

0

答案是:

class Role { 
    Movie movie 
    Person person 
    String fuGorm 

    def move(Person newbie) { 
     def m = this.movie?.id 
     def p = this.person?.id 
     def n = newbie?.id 

     // bypass GORM and issue a raw SQL update command... 
     def q = "update ct_roles set person_id=$n where person_id=$p and movie_id=$m" 
     def success = runCommand(q) 

     if (success) { 
      // the above bypasses GORM, so we should still 
      // perform the operation using GORM speak 
      // otherwise our objects will be out of sync with the DB. 
      // The following EPIC FAILS to update the DB, 
      // but it does update the local Grails domain objects 
      this.person.removeFromRoles(this) 
      this.person = newbie 
      newbie.addToRoles(this) 
     } 
     return success 
    } 
    def runCommand = { query -> 
     def db = new Sql(dataSource) 
     db.execute (query) 
    } 
} 
0

尝试:

person1.removeFromRoles(角色)//角色是角色对象从哪个人要被移除
role.person = PERSON2

应该工作。

+0

谢谢,好主意,但电脑说“不(咳嗽)”。我实现了你的想法,这个想法在正确的方向上似乎正在取得进展,因为突然间我得到了ConcurrentModificationException,因为我在迭代它时正在修改角色列表。但是,一旦我改变了我的代码遍历表的副本,它仍然在完全相同:-(以同样的方式在一个理想的世界中发生故障时,“应努力”是可行的。 – 2012-08-15 19:23:36

+0

所以你刚才添加的'addToRoles'代码。 。我的回答值得一给予好评:P – 2012-08-16 05:07:36

+0

当然,你应得的给予好评感谢您的帮助,但我没有足够的代表 - #1不会让我 但是,没有,addToRoles也不是办法的!。这个解决方案的灵魂是原始的SQL更新,GORM完全无法对底层表做任何事情,这是几乎可以理解的,因为我们永远不应该改变主键,组合或其他方式,愚蠢的遗留数据库addToRoles只是确保Grails对数据库的新状态有一个准确的描述。 – 2012-08-25 09:01:02