2011-03-15 115 views
6

我试图保存具有多关系的对象。 SellingCompany可以有许多帐户,并且一个帐户可以与许多SellingCompanies关联。因此,有存储在SellingCompaniesAccount的表之间的多对多关系在grails中保存具有多对多关系的对象

我ACCOUNT_INFO域如下:

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}" 
    } 
} 

我SellingComapanies域如下:

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文件中的表单包含实际遍历所有不同SellingCompanies并显示为复选框的代码。

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

最后是处理保存和列表功能的控制器。

class SellingCompaniesAccountController { 

    private static Logger log = Logger.getLogger(SellingCompaniesAccountController.class) 

    //def index = { } 
    //def scaffold = true 

    def index = { redirect(action:list,params:params) } 

    //To limit access to controller actions based on the HTTP request method. 
    def allowedMethods = [save:'POST'] 

    //create.gsp exists 
    def create = { 
     render(view:"create") 
    } 

    //edit.gsp exists 
    //def edit = {} 

    //list.gsp exists 
    def list = { 
     [ sellingCompaniesAccountInstanceList: SellingCompaniesAccount.list(max:15) ] 
     } 

    //show.gsp exists 
    //def show={} 

    //save.gsp exists 
    def save = { 
     log.info "Saving: " + params.toString() 

     println("Saving: " + params.toString()) 
     def sellingCompaniesAccount = params.sellingCompaniesAccount 
     println(sellingCompaniesAccount) 

     def sellingCompanies = params.sellingCompanies 

     log.info "sellingCompanies: " + sellingCompanies 
     println(sellingCompanies) 


     def sellingCompaniesAccountInstance = new SellingCompaniesAccount(name: params.name) 

     println(params.name) 

     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) 
     } 
     log.info sellingCompaniesAccountInstance 
     if (sellingCompaniesAccountInstance.save(flush: true)) { 
      flash.message = "${message(code: 'default.created.message', args: [message(code: 'sellingCompaniesAccountInstance.label', default: 'sellingCompaniesAccountInstance'), sellingCompaniesAccountInstance.id])}" 
      redirect(action: "show", id: sellingCompaniesAccountInstance.id) 
      log.info sellingCompaniesAccountInstance 
     } 
     else { 
      render(view: "create", model: [sellingCompaniesAccountInstance: sellingCompaniesAccountInstance]) 
     } 


    } 

} 

现在,我收到以下错误,由于出现类似_sellingcompanies_1等:

错误日志空的隐藏价值:

Saving: ["accountInfo.id":"1", "accountInfo":["id":"1"], "_sellingcompanies_5":"", "_isActive":"", "code":"test", "agency_name":"test", "sellingcompanies_4":"4", "sellingcompanies_5":"5", "create":"Create", "isActive":"on", "iata":"test", "agency_id":"test", "contactinfo.id":"1", "contactinfo":["id":"1"], "consultant_id":"test", "sellingcompanies_2":"2", "_sellingcompanies_1":"", "sellingcompanies_3":"3", "_sellingcompanies_2":"", "_sellingcompanies_3":"", "sellingcompanies_1":"1", "_sellingcompanies_4":"", "action":"save", "controller":"sellingCompaniesAccount"] 
null 
null 
null 
2011-03-15 17:13:44,620 [http-8080-2] ERROR org.codehaus.groovy.grails.web.errors.GrailsExceptionResolver - For input string: "_5" 
java.lang.NumberFormatException: For input string: "_5" 
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) 
    at java.lang.Integer.parseInt(Integer.java:449) 
    at java.lang.Integer.valueOf(Integer.java:554) 
    at content_hub_admin.SellingCompaniesAccountController$_closure4_closure5.doCall(content_hub_admin.SellingCompaniesAccountController:70) 
    at content_hub_admin.SellingCompaniesAccountController$_closure4.doCall(content_hub_admin.SellingCompaniesAccountController:66) 
    at content_hub_admin.SellingCompaniesAccountController$_closure4.doCall(content_hub_admin.SellingCompaniesAccountController) 
    at java.lang.Thread.run(Thread.java:680) 

首先,哪里隐藏值来自并且这种方法可以很好地提交SellingCompaniesAccount控制器类中的Many-Many关系信息。任何更好的做法。

的create.gsp解析到此浏览器:提前 enter image description here

感谢

+1

你应该限制相关的代码,它有助于其他阅读更容易和理解你的问题。 – 2011-03-16 08:13:37

+0

作为日志指出,这是一个数据类型错误。你看看SellingCompaniesAccountController第70行吗? – 2011-03-16 08:16:24

+0

感谢黄龙在调查后发现该复选框呈现隐藏字段。如何禁用该隐藏字段?有任何想法吗。如何为每个选中的复选框在SellingCompaniesAccount表中添加记录。 – 2011-03-16 09:37:20

回答

1

的问题是这段代码:

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) 
    } 

您从表单post数据是:

Saving: ["accountInfo.id":"1", "accountInfo":["id":"1"], "_sellingcompanies_5":"", "_isActive":"", "code":"test", "agency_name":"test", "sellingcompanies_4":"4", "sellingcompanies_5":"5", "create":"Create", "isActive":"on", "iata":"test", "agency_id":"test", "contactinfo.id":"1", "contactinfo":["id":"1"], "consultant_id":"test", "sellingcompanies_2":"2", "_sellingcompanies_1":"", "sellingcompanies_3":"3", "_sellingcompanies_2":"", "_sellingcompanies_3":"", "sellingcompanies_1":"1", "_sellingcompanies_4":"", "action":"save", "controller":"sellingCompaniesAccount"] 

循环中的测试首先检查参数关键字是否包含“_出售公司”,然后它什么都不做;第二部分检查参数关键字是否包含“销售公司 _”,然后它试图从该参数值拉出后缀数字。如果参数的键值为“_sellingcompanies_5”,则第一次测试和第二次测试的结果均为真,因此在第二次测试中,您将从参数关键值中扣除“销售公司_”,而您留下“_5”,然后你试图评估一个整数。不幸的是,“_5”不是一个有效的整数值,因此你给出的错误。

您可以通过以下操作非常简单地解决这个问题:

params.each { 
    if (it.key.startsWith("sellingcompanies")) { 
     sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer) 
    } 
} 

可能是一个更好的方式来处理这虽然会改变你的GSP给予同样的命名参数为每个sellingcompanies,然后循环实际应用的值。事情是这样的:

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

然后在你的控制器做这样的事情:

params.sellingcompanies = [params.sellingcompanies].flatten() as String[] 

sellingCompaniesAccountInstance.sellingCompaniesId = params.sellingcompanies.collect { SellingCompanies.get(it) } 

这应该确保你正确地评价已经从你的模型对象传递适当的值,而不是黑客在检索方法中。

希望这会有所帮助!

2

如果其他人是否有同样的问题,然后由丹尼尔上面的回答是绝对正确的只是添加为的Grails的一些变化2.7.8

所有复选框,会有相同的值=“$ {} item.id”和名称=“sellingcompanies”如图所示如下─

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

最好的部分是Grails中的当前版本,你不会需要使用“扁平化()作为字符串”由丹尼尔提到的这些值会自动进行处理grails,并将在连接表中保留。所有你需要确定的是你的复选框有正确的名称和价值。

希望它有帮助!