【问题标题】:Grails 2.4.4 removing all items from a hasmany String relationshipGrails 2.4.4 从 hasmany String 关系中删除所有项目
【发布时间】:2015-11-23 07:55:46
【问题描述】:

我有一个 User 类,它有很多组织,组织是字符串 UID。

class User implements Serializable {
  ...
  List organizations
  static hasMany = [organizations: String]
  ...
}

要更新用户实例,我需要在添加更新后的 uid 之前从“组织”中删除所有字符串,但它不起作用。在我删除它们并保存用户实例后,相同的组织将重新保存到集合中。

我尝试了很多方法:

// 1
user.organizations.clear()

// 2
def orgsToDelete = [] // this is to avoid concurrent modification exception
orgsToDelete += user.organizations
orgsToDelete.each { orguid ->
   user.removeFromOrganizations(orguid)
}

在 1 或 2 之后,user.organizations 为空,但当我这样做时:

user.save(flush:true)

我得到了与 clear/removeFromOrganizations 之前相同的组织

我不能做 user.organizations.each { it.delete() } 因为项目不是域类而是字符串。

另一个奇怪的事情是我有一个自定义验证器来检查集合是否有任何项目,并且它似乎没有收到任何错误,如果组织是空的,这是我的验证器:

organizations validator: { val, obj ->
  if (obj.organizations.size() == 0) return false
  return true
}

当我对控制器更新操作执行此操作时,它显示 hasErrors() == false

if (userInstance.hasErrors())
{
   println "has errors"
   respond userInstance.errors, view:'edit'
   return
}

有什么想法吗?

这里是控制器:https://github.com/ppazos/cabolabs-ehrserver/blob/master/grails-app/controllers/com/cabolabs/security/UserController.groovy#L199-L237

【问题讨论】:

    标签: grails


    【解决方案1】:

    使用您自己的域类而不是 String 作为集合的元素,例如:

    class Organization {
      String name
      static belongsTo = [ User ]
    }
    

    那么您应该能够通过

    正确删除孩子
    user.organisations.clear()
    user.save()
    

    您所面临的行为的原因是,String 实例被映射到一个表,该表没有指向user 的反向引用。这导致了这种情况,string 表中的记录实际上并未被删除,而是在下一次数据库调用时加载。

    【讨论】:

    • 字符串“user_organizations”的映射表有一个 user_id,但我注意到它没有设置为“user”表的 FK。让我改写你的答案,因为这可能是一个 Grails 错误:不可能从 hasMany String 关系中删除项目?
    • 我不认为这是一个错误。在 Hibernate 中(不在 Grails 中)Strings 不应该是域对象
    • 我知道字符串不是域对象。但我要指出的是,Grails 支持将字符串声明和添加到 hasMany 关系的这一特性,但它似乎不支持从关系中删除项目。如果支持“添加”,我通常希望也支持“删除”。你怎么看?谢谢!
    • 我认为,如果您需要在域模型中包含一个字符串数组,最好的方法是使用 noSQL DB,因为没有 RDBMS 支持它们。因此,hibernate/GORM 只为这种不太优雅的聚合提供了一种解决方法。
    【解决方案2】:

    我已阅读您的项目代码,并且您的 DataSource 设置错误。您使用的是 H2 内存 BBDD,但使用的是 MySQL 驱动程序(在开发环境中)。它看起来不太好。请正确设置,然后重试。

    我已经测试了你的模型,并使用了:

    user.organizations.clear()
    

    没有任何问题,即使使用您的自定义验证器。

    另一方面,您应该为所有业务逻辑使用服务,而不是控制器。因为服务默认是事务性的。

    以下是我所做的更改,并且有效:

    //   List organizations = []
       static hasMany = [organizations: String] 
    
       static mapping = {
          password column: '`password`'
          // organizations lazy: false
       }
    

    删除列表组织。在 DataSource 开发环境中使用带有此配置的 H2 数据源:

           dbCreate = "create-drop" 
           url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
           username = "sa"
           password = ""
    

    这段代码就像一个魅力:

       def clearOrganizationFromUser(){
    
          //creating user with timestamp
          User user = new User(username: 'username' + new Date(), password: 'password', email: 'email@email.es', accountExpired: false, accountLocked: false,
             passwordExpired: false)
          List<String> organizations = []
          10.times{
             organizations << "organization $it"
          }
    
          organizations.each{ String organization ->
             user.addToOrganizations(organization)
          }
    
          user.save()
          println "Organizations after saving: ${user.organizations}"
    
          //Its not neccesary but I did it for showing that organization are persisted in DDBB
          User newUserFromDDBB = User.get(user.id)
    
          //deleting organization
          newUserFromDDBB.organizations.clear()
          newUserFromDDBB.save()
    
          println "---> Organizations after deleting: ${newUserFromDDBB.organizations}"
    
       }
    

    希望它有效。如果有,请标记为已解决。

    【讨论】:

    • 它只用 H2 设置 url,然后它被重置为 mysql:url url = "jdbc:mysql://$host:$port/$dbName" 它工作正常,但我可以评论第一个url集。
    • 我可以给你发一个项目演示。也许有帮助
    • 拜托,我想检查一下差异,因为我测试了 .clear() 并且不适合我。您要发送 PR 吗?只是为了查看 github 上的差异。谢谢!
    • 知道了,我认为问题可能是因为我使用 MySQL 而不是 H2 进行开发和生产,这可能与 H2 如何管理 FK 有关,因为在 .clear() 之后我在 user.organizations 下再次获取组织字符串。如果组织字符串已从 user_organizations 表中删除,您是否在 H2 控制台中看到过?在我的数据库上没有发生。
    • 不,很抱歉,但在代码末尾我通过 id 查询新的用户实例,并且没有组织,所以我猜它们被删除了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多