2011-03-15 113 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,並將在連接表中保留。所有你需要確定的是你的複選框有正確的名稱和價值。

希望它有幫助!