在grails中保存具有多对多关系的对象

在grails中保存具有多对多关系的对象,grails,groovy,save,has-many,Grails,Groovy,Save,Has Many,我试图保存具有许多关系的对象。一个销售公司可以有多个帐户,并且一个帐户可以与多个销售公司关联。因此,SellingCompanyAccount中存储的表之间存在许多关系 我的帐户信息域如下所示: class AccountInfo { static mapping ={ table 'AccountInfo' version false //id column:'accountInfoID' } String evi_p

我试图保存具有许多关系的对象。一个销售公司可以有多个帐户,并且一个帐户可以与多个销售公司关联。因此,SellingCompanyAccount中存储的表之间存在许多关系

我的帐户信息域如下所示:

class AccountInfo { 
    static mapping ={
        table 'AccountInfo'
        version false
        //id column:'accountInfoID'
    }

    String evi_pass_phrase
    String evi_username
    String security_key

    // to make sure fields show up in a particular order

    static constraints = {
        //accountInfoID(insert:false,update:false)
        evi_pass_phrase()
        evi_username()
        security_key()

    }

    static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]


    String toString() {
        return "${evi_username}"
    }
}
class SellingCompanies 
{

    static mapping = {  
        table 'SellingCompanies'
        version false
    }

    String name

    //static belongsTo = AccountInfo

    //static hasMany = [accounts: AccountInfo]
    static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]

    static constraints = {

    name(blank:false, validator:
        { val, obj ->
            def similarSellingCompanies = SellingCompanies.findByNameIlike(val)
            return !similarSellingCompanies || (obj.id == similarSellingCompanies.id)
        })
    }

    //String toString() { name }
}
class SellingCompaniesAccount {

    static constraints = {
        // ensure the group of sellingCompaneis and accountInfo values are unique
        agency_name(unique:['sellingCompanies','accountInfo'])
    }

    int agency_id
    String agency_name
    String consultant_id
    String code
    Boolean isActive
    String iata

    ContactInfo contactinfo

    static belongsTo = [sellingCompanies:SellingCompanies, accountInfo:AccountInfo]

        }

}
我的SellingComapanies域如下:

class AccountInfo { 
    static mapping ={
        table 'AccountInfo'
        version false
        //id column:'accountInfoID'
    }

    String evi_pass_phrase
    String evi_username
    String security_key

    // to make sure fields show up in a particular order

    static constraints = {
        //accountInfoID(insert:false,update:false)
        evi_pass_phrase()
        evi_username()
        security_key()

    }

    static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]


    String toString() {
        return "${evi_username}"
    }
}
class SellingCompanies 
{

    static mapping = {  
        table 'SellingCompanies'
        version false
    }

    String name

    //static belongsTo = AccountInfo

    //static hasMany = [accounts: AccountInfo]
    static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]

    static constraints = {

    name(blank:false, validator:
        { val, obj ->
            def similarSellingCompanies = SellingCompanies.findByNameIlike(val)
            return !similarSellingCompanies || (obj.id == similarSellingCompanies.id)
        })
    }

    //String toString() { name }
}
class SellingCompaniesAccount {

    static constraints = {
        // ensure the group of sellingCompaneis and accountInfo values are unique
        agency_name(unique:['sellingCompanies','accountInfo'])
    }

    int agency_id
    String agency_name
    String consultant_id
    String code
    Boolean isActive
    String iata

    ContactInfo contactinfo

    static belongsTo = [sellingCompanies:SellingCompanies, accountInfo:AccountInfo]

        }

}
包含多个关系的表如下所示:

class AccountInfo { 
    static mapping ={
        table 'AccountInfo'
        version false
        //id column:'accountInfoID'
    }

    String evi_pass_phrase
    String evi_username
    String security_key

    // to make sure fields show up in a particular order

    static constraints = {
        //accountInfoID(insert:false,update:false)
        evi_pass_phrase()
        evi_username()
        security_key()

    }

    static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]


    String toString() {
        return "${evi_username}"
    }
}
class SellingCompanies 
{

    static mapping = {  
        table 'SellingCompanies'
        version false
    }

    String name

    //static belongsTo = AccountInfo

    //static hasMany = [accounts: AccountInfo]
    static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]

    static constraints = {

    name(blank:false, validator:
        { val, obj ->
            def similarSellingCompanies = SellingCompanies.findByNameIlike(val)
            return !similarSellingCompanies || (obj.id == similarSellingCompanies.id)
        })
    }

    //String toString() { name }
}
class SellingCompaniesAccount {

    static constraints = {
        // ensure the group of sellingCompaneis and accountInfo values are unique
        agency_name(unique:['sellingCompanies','accountInfo'])
    }

    int agency_id
    String agency_name
    String consultant_id
    String code
    Boolean isActive
    String iata

    ContactInfo contactinfo

    static belongsTo = [sellingCompanies:SellingCompanies, accountInfo:AccountInfo]

        }

}
create.gsp文件中的表单包含实际迭代所有不同SellingCompany的代码,并显示为复选框

<g:form action="save" method="post">
    <div class="dialog">
    <table width="500px" border="0px" color="red">
        <tbody>

            <tr class="prop">
                <td valign="top" class="name"><label for="accountInfo"><g:message
                    code="sellingCompaniesAccount.accountInfo.label"
                    default="Account Info" /></label></td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'accountInfo', 'errors')}">
                <g:select name="accountInfo.id"
                    from="${content_hub_admin.AccountInfo.list()}" optionKey="id"
                    value="${sellingCompaniesAccountInstance?.accountInfo?.id}" /></td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="sellingCompanies"><g:message
                    code="sellingCompaniesAccount.sellingCompanies.label"
                    default="Selling Companies" /></label></td>
                <td valign="top"
                    class="">
                    <g:each in="${content_hub_admin.SellingCompanies.list()}" var="item" status="i">
                        ${++i}.  ${item.name}&nbsp;&nbsp;<g:checkBox name="sellingcompanies_${++i-1}" optionKey="id" value="${item.id}" /> <br>
                    </g:each>
                <!--  end here by rsheyeah -->
                </td>
            </tr>



            <tr class="prop">
                <td valign="top" class="name"><label for="code"><g:message
                    code="sellingCompaniesAccount.code.label" default="Code" /></label></td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'code', 'errors')}">
                <g:textField name="code"
                    value="${sellingCompaniesAccountInstance?.code}" /></td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="agency_name"><g:message
                    code="sellingCompaniesAccount.agency_name.label"
                    default="Agencyname" /></label></td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'agency_name', 'errors')}">
                <g:textField name="agency_name"
                    value="${sellingCompaniesAccountInstance?.agency_name}" /></td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="isActive"><g:message
                    code="sellingCompaniesAccount.isActive.label" default="Is Active" /></label>
                </td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'isActive', 'errors')}">
                <g:checkBox name="isActive"
                    value="${sellingCompaniesAccountInstance?.isActive}" /></td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="agency_id"><g:message
                    code="sellingCompaniesAccount.agency_id.label" default="Agencyid" /></label>
                </td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'agency_id', 'errors')}">
                <g:textField name="agency_id"
                    value="${fieldValue(bean: sellingCompaniesAccountInstance, field: 'agency_id')}" />
                </td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="iata"><g:message
                    code="sellingCompaniesAccount.iata.label" default="Iata" /></label></td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'iata', 'errors')}">
                <g:textField name="iata"
                    value="${sellingCompaniesAccountInstance?.iata}" /></td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="consultant_id"><g:message
                    code="sellingCompaniesAccount.consultant_id.label"
                    default="Consultantid" /></label></td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'consultant_id', 'errors')}">
                <g:textField name="consultant_id"
                    value="${sellingCompaniesAccountInstance?.consultant_id}" /></td>
            </tr>

            <tr class="prop">
                <td valign="top" class="name"><label for="contactinfo"><g:message
                    code="sellingCompaniesAccount.contactinfo.label"
                    default="Contactinfo" /></label></td>
                <td valign="top"
                    class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'contactinfo', 'errors')}">
                <g:select name="contactinfo.id"
                    from="${content_hub_admin.ContactInfo.list()}" optionKey="id"
                    value="${sellingCompaniesAccountInstance?.contactinfo?.id}" /></td>
            </tr>

        </tbody>
    </table>
    </div>
    <div class="buttons"><span class="button"><g:submitButton
        name="create" class="save"
        value="${message(code: 'default.button.create.label', default: 'Create')}" /></span>
    </div>
</g:form>
首先,隐藏值从何而来?这种方法可以提交SellingCompanysAccount控制器类中的多个关系信息吗。任何更好的方法

create.gsp在浏览器中解析为:


提前感谢

这段代码有问题:

    params.each {
        if (it.key.contains("_sellingcompanies"))
        //sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
        if (it.key.contains("sellingcompanies_"))
            sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
    }
循环中的测试首先检查参数键是否包含“\uSellingCompanys”,然后它什么也不做;第二部分检查参数键是否包含“sellingcompanys_u2;”,然后尝试从该参数值中提取带后缀的数字。对于键值为“_sellingcompanies_5”的参数,第一个测试和第二个测试的计算结果均为true,因此在第二个测试中,您将从参数键值中减去“sellingcompanies_”,并留下“_5”,然后尝试将其计算为整数。不幸的是,“_5”不是一个有效的整数值,因此出现了给定的错误

您可以通过执行以下操作非常简单地解决此问题:

params.each {
   if (it.key.startsWith("sellingcompanies")) {
      sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
   }
}
这应该确保您正确地评估从模型对象传递的适当值,而不是侵入检索方法


希望这有帮助

如果其他人也有同样的问题,那么上面Daniel的回答是绝对正确的,只是添加了Grails 2.7.8中的一些更改

所有复选框都将具有相同的
value=“${item.id}”
name=“SellingCompanys”
,如下所示:

<!-- ... snip ... -->
    <tr class="prop">
        <td valign="top" class="name"><label for="sellingCompanies"><g:message
            code="sellingCompaniesAccount.sellingCompanies.label"
            default="Selling Companies" /></label></td>
        <td valign="top"
            class="">
            <g:each in="${content_hub_admin.SellingCompanies.list()}" var="item" status="i">
                ${++i}.  ${item.name}&nbsp;&nbsp;<g:checkBox name="sellingcompanies" optionKey="id" value="${item.id}" /> <br>
            </g:each>
        <!--  end here by rsheyeah -->
        </td>
    </tr>
    <!-- ... snip ... -->

${++i}${item.name}
最好的部分是,在当前版本的Grails中,您不需要像Daniel提到的那样使用
flatte()作为字符串
,这些值将由Grails自动处理,并保存在联接表中。您只需确保复选框具有正确的名称和值


希望有帮助

您应该限制相关的代码,这有助于其他人更轻松地阅读并理解您的问题。正如日志所指出的,这是一个数据类型错误。你看过SellingCompanysAccountController第70行了吗?谢谢Hoang Long,在调查之后,我发现复选框呈现了一个隐藏字段。如何禁用这个隐藏字段?任何想法。以及如何在SellingCompanyAccount表中为每个选中的复选框添加记录。非常确定隐藏字段在那里,以便您可以“取消选中”复选框。表单无法提交“未选中”的复选框值,因此,如果复选框已选中,但您已取消选中,则必须存在隐藏字段,以让属性解析程序知道该属性过去已被选中。