6

私は現在Grailsアプリケーションを開発しており、SpringSecurityおよび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]

}

クラスからわかるように、1人のユーザーを1つのエリアにリンクできますが、エリアには多くのユーザーがいる場合があります。これはすべて正常に機能し、アプリケーションをブートストラップすると、すべてのデータが正しく追加されます。ただし、フォームを使用して新しいユーザーを作成しようとすると、次のエラーが発生します。

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

以下は、情報を保存するために使用しているコントローラーコードです。

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」関数を試しましたが、ほとんど成功しませんでした

可能であれば、これについて助けていただければ幸いです。

ありがとう

編集 ......

私はコントローラーでこの行の問題を追跡しました:

RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)

これは、この関数がユーザーオブジェクトの保存関数を呼び出していることを示していますが、関係が整っている場合は、最初にエリアを保存する必要があります。これについて私を助けるためにSpringSecurityUiを知っている人はいますか?

ありがとう

4

3 に答える 3

8

表示されるエラーメッセージ

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)

レジスタ呼び出しの前に、 RegistrationCode.registerメソッドをロジックで更新して、エリアをユーザーに割り当てる必要があります(エリアがすでに存在していると仮定します) 。以下は簡単な例です。

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ビューから「area.name」を返しているので、RegisterCommandを更新/オーバーライドしてエリア名を含める必要があります
  • エリア「名前」を識別子として使用しても安全ですか?クラス定義では、「名前」が一意になることを示す制約はありません。たぶん、あなたのビューからエリアIDを返す方が安全です
  • 理想的には、カスタムプロパティエディタを使用してエリアルックアップを処理する必要があります-ここに例があります: Grailsコマンドオブジェクトデータバインディング

とにかく、それが役立つことを願っています。

于 2012-10-23T09:34:36.730 に答える
0

双方向の依存関係を反対側に向けてみてください

class Areas {

    String name
    static belongsTo = [User] 
    static hasMany = [users:User]
}

ユーザーからbelongsToを削除することを忘れないでください

于 2012-10-23T09:09:02.083 に答える
0
class Areas {
    String name
    static belongsTo = [User] 
    static hasMany = [users:User]
}
于 2014-01-08T10:46:44.680 に答える