是否可以在Grails的Bootstrap.groovy中显式设置域对象的id(或者就此而言在任何地方)?
我尝试了以下内容:
new Foo(id: 1234, name: "My Foo").save()
和
def foo = new Foo()
foo.id = 1234
foo.name = "My Foo"
foo.save()
但是在这两种情况下,当我在运行时打印出Foo.list()
的结果时,我看到我的对象的id为1,或者序列中的下一个id是。
修改 这是在Grails 1.0.3中,当我使用内置的HSQL数据库在'dev'中运行我的应用程序时。
修改
chanwit提供了one good solution below。但是,我实际上正在寻找一种方法来设置id而不更改我的域的id生成方法。这主要用于测试:我希望能够在我的测试引导程序或setUp()
中将某些内容设置为已知的id值,但仍然可以在生产中使用auto_increment或序列。
答案 0 :(得分:10)
是的,手动GORM映射:
class Foo {
String name
static mapping = {
id generator:'assigned'
}
}
和你的第二个片段(不是第一个片段)将完成这项工作(在通过构造函数传递时不会分配Id。)
答案 1 :(得分:1)
我最终使用的解决方法是不尝试通过其ID来检索对象。因此,对于问题中给出的示例,我更改了我的域对象:
class Foo {
short code /* new field */
String name
static constraints = {
code(unique: true)
name()
}
}
然后我使用enum
来保存代码的所有可能值(它们是静态的),并通过使用适当的枚举值执行Foo
来检索Foo.findByCode()
个对象(而不是像我之前想做的那样使用带有id的Foo.get()
。
这不是最优雅的解决方案,但它对我有用。
答案 2 :(得分:1)
作为替代方案,假设您正在导入数据 或从现有应用程序迁移数据 ,出于测试目的,您可以在Bootstrap文件中使用本地地图。可以把它想象成带有好处的import.sql; - )
使用这种方法:
干杯!
def init = { servletContext ->
addFoos()
addBars()
}
def foosByImportId = [:]
private addFoos(){
def pattern = ~/.*\{FooID=(.*), FooCode=(.*), FooName=(.*)}/
new File("import/Foos.txt").eachLine {
def matcher = pattern.matcher(it)
if (!matcher.matches()){
return;
}
String fooId = StringUtils.trimToNull(matcher.group(1))
String fooCode = StringUtils.trimToNull(matcher.group(2))
String fooName = StringUtils.trimToNull(matcher.group(3))
def foo = Foo.findByFooName(fooName) ?: new Foo(fooCode:fooCode,fooName:fooName).save(faileOnError:true)
foosByImportId.putAt(Long.valueOf(fooId), foo) // ids could differ
}
}
private addBars(){
...
String fooId = StringUtils.trimToNull(matcher.group(5))
def foo = foosByImportId[Long.valueOf(fooId)]
...
}