问题
I have data writing to a mongoDB database with issues using integration tests and the Grails scaffolding. When trying to select a domain instance from the 'list' type page, I get the error "[domain name] not found with id null".
I am sure it is because of the Grails url [controller]/[action]/[id]. This id is a string and needs to be converted to an ObjectId for Grails queries.
Is there a way to do this so that it affects a specified domain or even better yet, all of the domains at once?
I guess as I'm writing my app, I can convert it to an ObjectId from within the action method, but I'd like to have the scaffolding work or provide a global solution.
回答1:
I believe this is happening because the show() method (that the Grails scaffolding functionality generates as an action) accepts an id parameter of type Long ie.
def show(Long id) {
def suiteInstance = Suite.get(id)
if (!suiteInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'suite.label', default: 'MyDomainClass'), id])
redirect(action: "list")
return
}
[suiteInstance: suiteInstance]
}
which binds the id parameter to the argument. Because the ObjectId can't be converted to a Long, it ends up being null, hence the call to MyDomainClass.get(id) fails with the error message.
You can get around this by overriding the show() action in your scaffolded controller so that it expects an ObjectId or String, but I would say the proper fix for this is to update the Grails scaffolding plugin so it is a little more liberal in the types of IDs it accepts.
回答2:
I had this problem as well. You can keep the domain object id as an ObjectId and update the controller as follows:
domain Object:
import org.bson.types.ObjectId;
class DomainObject {
ObjectId id
// Add other member variables...
}
Controller:
def show(String id) {
def domainObjectInstance = domainObject.get(new ObjectId(id))
if (!domainObjectInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'domainObject.label', default: 'DomainObject'), id])
redirect(action: "list")
return
}
[domainObjectInstance: domainObjectInstance]
}
You would also need to update your other controller methods that use id as well such as edit, update etc.
Additionally, if you want the grails default controller generation to work like this for all your domain objects you can update the template as coderLMN suggests.
回答3:
The get(params.id) call in show() method will NOT convert params.id String to an ObjectId object, so the domain instance will be null, then the following code takes you to list action with an error message:
if (!exampleInstance) { flash.message = message(code: 'default.not.found.message', args: [message(code: 'example.label', default: 'Example'), params.id]) redirect(action: "list") return }
Possible solutions:
you can run "grails install-template" command, so that the scaffolding templates in src/templates/scaffolding/ directory can be modified. Then you have new scaffold ready to generate customized controllers, views, tests for all your Domain classes.
A simpler solution is to define the id property as String instead of ObjectId. A String id will be equal to objectId.toString(), in this case your scaffold will work.
回答4:
In domain classes keep you id type as ObjectId and keep scaffold = true for all respective controllers.
In Domain class :
ObjectId id
In respective controller :
static scaffold = true
Clear all existing collections from Mongo
I guess that's sufficient to have Grails-Mongo app up & running, considering you have correctly configured mongo-plugin
来源:https://stackoverflow.com/questions/13907221/grails-with-mongodb-object-id-and-scaffold