繁体   English   中英

Grails-将关联的域对象分配给List与ArrayList

[英]Grails- Assigning associated domain objects into List vs ArrayList

我有这种关系:

User{
...
hasMany = [tags: Tag]

}

Tag{
...
}

在我的服务中,我有以下代码:

List<Tag> tags = user.tags

但这不起作用,我收到此错误:


org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[com.app.ext.Tag : 1]' with class 
'org.hibernate.collection.PersistentSet' to class 'java.util.List' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.List(com.app.ext.Tag)
    at ConsoleScript15.run(ConsoleScript15:6)

如果我将代码更改为:

ArrayList<Tag> tags = user.tags

它按预期工作! 尽管ArrayListList子类。 有什么解释吗?

Grails版本: 2.3.0

看一下Groovy的转换规则

当您尝试转换的值是collection时,将调用您要转换为的类型的构造函数。 因此,对于ArrayList它隐式调用:

ArrayList<Tag> tags = new ArrayList(users.tags)

对于List ,它将类似于new List(users.tags) ,这是不正确的,因为List是接口。

下面的代码段显示了相同的问题:

Set<String> mySet = new HashSet<>(['A', 'B'])
ArrayList<String> myList = mySet; // works okay
List<String> myList = mySet; // fails with GroovyCastException

但是您可以显式转换为ArrayList

List<String> myList = mySet as ArrayList; 

定义hasMany属性时,格式为Map。 您的伪代码不正确,使用{}而不是[]。 实际的代码可能更像

static hasMany = [tags: Tag]

Tag将集合成员类型指定为Tag域类,并且tags可以是任何合法变量名称。 通常,它是类名的小写和复数形式,但这只是一个约定。

AST转换使用此信息Set名为tagsSet属性编译到您的类中,本质上是这样的:

Set<Tag> tags

以及您是否使用了其他名称,例如

static hasMany = [puppies: Tag]

那你就有

Set<Tag> puppies

Set不是List ,反之亦然-集合保证唯一性,并列出保证顺序。

您可以在Groovy中非常轻松地将一个转换为另一个,如果这就是您要尝试的方法,那么另一个答案应该会有所帮助。 但是考虑到原始类型是Set ,则将项目添加到List毫无意义,因为顺序将是随机的。

您可以将集合的类型声明为列表,然后Hibernate将添加一个额外的列来存储元素索引,以确保列表中的顺序保留在数据库中。 为此,显式添加一个List声明

List tags
static hasMany = [tags: Tag]

还建议您检查grails指南,因为那里说hasMany关系是默认情况下的Map http://grails.github.io/grails-doc/3.0.x/guide/GORM.html #domainClasses ,如果需要,则必须显式地将变量声明为Set

  public class Car{
      Set<Tyre> tyres

      static has many = [tyres:Tyre, seats:Seat]
 }

在这种情况下,将确保轮胎的唯一性,因为它是一个Set,而不会为座椅提供唯一性,因为默认情况下它是Map

希望这也会有所帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM