Grails with MongoDB, Object id, and scaffold

痴心易碎 提交于 2019-12-10 11:17:49

问题


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:

  1. 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.

  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!