Grails - 在刷新 grails 错误之前保存 transient 实例?

标签 grails grails-orm save domain-model

我目前正在开发 Grails 应用程序,并且正在使用 Spring Security 和 UI 插件。我已经创建了用户类和我拥有的另一个区域类之间的关系,如下所示:

用户类别:

class User {

    transient springSecurityService

    String username
    String email
    String password
    boolean enabled
    boolean accountExpired
    boolean accountLocked
    boolean passwordExpired

    static belongsTo = [area:Areas]

        .......
}

区域等级:
class Areas {

    String name

    static hasMany = [users:User]

}

从类中可以看出,一个用户可以链接到一个区域,但一个区域可能有很多用户。这一切正常,当我引导应用程序时,所有数据都被正确添加。但是,当我尝试使用表单创建新用户时出现以下错误:
object references an unsaved transient instance - save the transient instance before flushing: com.website.Area

下面是我用来保存信息的 Controller 代码:
def save = {    
        def user = lookupUserClass().newInstance(params)

        if (params.password) {
            String salt = saltSource instanceof NullSaltSource ? null : params.username
            user.password = springSecurityUiService.encodePassword(params.password, salt)
        }

        if (!user.save(flush: true)) {
            render view: 'create', model: [user: user, authorityList: sortedRoles()]
            return
        }

        addRoles(user)
        flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.id])}"
        redirect action: edit, id: user.id
    }

以下是 GSP 的示例:
<table>
        <tbody>

            <s2ui:textFieldRow name='username' labelCode='user.username.label' bean="${user}"
                            labelCodeDefault='Username' value="${user?.username}"/>

            <s2ui:passwordFieldRow name='password' labelCode='user.password.label' bean="${user}"
                                labelCodeDefault='Password' value="${user?.password}"/>

            <s2ui:textFieldRow name='email' labelCode='user.email.label' bean="${user}"
                                labelCodeDefault='E-Mail' value="${user?.email}"/>

            <s2ui:textFieldRow readonly='yes' name='area.name' labelCode='user.area.label' bean="${user}"
                                labelCodeDefault='Department' value="${area.name}"/>


            <s2ui:checkboxRow name='enabled' labelCode='user.enabled.label' bean="${user}"
                           labelCodeDefault='Enabled' value="${user?.enabled}"/>

            <s2ui:checkboxRow name='accountExpired' labelCode='user.accountExpired.label' bean="${user}"
                           labelCodeDefault='Account Expired' value="${user?.accountExpired}"/>

            <s2ui:checkboxRow name='accountLocked' labelCode='user.accountLocked.label' bean="${user}"
                           labelCodeDefault='Account Locked' value="${user?.accountLocked}"/>

            <s2ui:checkboxRow name='passwordExpired' labelCode='user.passwordExpired.label' bean="${user}"
                           labelCodeDefault='Password Expired' value="${user?.passwordExpired}"/>
        </tbody>
        </table>

我已经研究过这个,我相信这是我试图保存 GORM 对象的方式,我应该在尝试保存用户之前保存父(区域)。但是在创建用户之前该区域将始终存在,因此我不需要再次创建该区域,我该如何处理?我也尝试了“withTransaction”功能,但收效甚微

如果可能的话,我真的很感激这方面的一些帮助。

谢谢

编辑 ......

我已将问题跟踪到 Controller 中的这一行:
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)

这对我说这个函数正在为用户对象调用一个保存函数,但是有了适当的关系,它需要先保存区域。有谁知道 SpringSecurityUi 以帮助我解决这个问题?

谢谢

最佳答案

你看到的错误信息

object references an unsaved transient instance - save the transient instance before flushing: com.website.Area

...当您尝试从子(即用户)实体中保存不存在的父(即区域)实体时会发生这种情况。 中可能发生错误RegistrationController.register 正如您所指出的那样,如果这是您保存新用户的地方。
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)

您只需要更新 注册码.注册 具有逻辑的方法在 之前将区域分配给用户(假设区域已经存在)注册 调用 - 下面是一个简单的例子。
class RegistrationController ..
 ..
def area = Area.findByName(command.areaName) 
def user = lookupUserClass().newInstance(email: command.email, username: command.username,
                accountLocked: true, enabled: true, area: area)
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)

一些注意事项:
  • 您正在从 gsp View 传回“area.name”,因此您需要更新/覆盖 RegisterCommand 以包含 区域姓名
  • 您使用的是 区域 “名称”作为标识符安全吗?在您的类定义中,您没有限制来表明“名称”将是唯一的。也许传回一个 区域您认为 id 更安全
  • 理想情况下,您应该处理 区域使用自定义属性编辑器查找 - 这是一个示例:Grails command object data binding

  • 无论如何,希望有帮助。

    关于Grails - 在刷新 grails 错误之前保存 transient 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13012272/

    相关文章:

    grails - Grails-在重定向参数中发送对象列表

    grails - 保存第二版本的grails对象

    javascript - 传递文件以保存到 php

    Redis数据库创建与值(value)提交

    grails - 如何管理一对多关系 - grails

    iphone - 如何为Grails应用创建移动界面?

    grails - 双向在哪里? grails 一对一,双向测试(继续)

    hibernate - Grails 域类事务

    grails - 在 grails 中建模多对一树

    C#保存数据 Access 数据库