[英]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
它按预期工作! 尽管ArrayList
是List
子类。 有什么解释吗?
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
名为tags
的Set
属性编译到您的类中,本质上是这样的:
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.