8 Replies Latest reply on Oct 2, 2008 8:48 PM by valatharv

    How to submit 2 form fields with same name

    valatharv
      I am new to seam not sure how to submit 2 form fields with same name, Please suggest, thanks in advance...

      We have one form which corresponds to different fields from different entities.

      Root is Study entity, which have OneToMany relation to QExp, QExp have OneToMany realtion with Region, all the mapping is fine.

      If there is ONE Region, i.e. one field like Pname, I am able to persist it.

      Issue comes up when we provide multiple form fields with same name for Region, (e.g. if there are 2  Pnames and both have value "#{regionHome.instance.pname}")
      After clicking "Save" values for Region 2 (PName) field is only persisted, which somehow overrides Region 1 (PName) field, it should svae both.

      We have a Entity "Region" and corresponding "regionhome", value for each region form field in xhtml is mapped to regionHome.instance.fieldname

      study.xhtml & studyHome.java does all the processing, studyHome.persist method is called on clicking save from study.xhtml.

      XHTML file :
      -----------
      <h:form id="studyForm">
      <rich:panel>
      <f:facet name="header">Region 1</f:facet>   
      <s:decorate id="pnameDecoration" template="layout/edit.xhtml">
           <ui:define name="label">PName</ui:define>
           <h:inputText id="name" required="true"
                           value="#{regionHome.instance.pname}"/>
      </s:decorate> 
      </rich:panel>

      <rich:panel>
      <f:facet name="header">Region 2</f:facet>   
      <s:decorate id="pnameDecoration" template="layout/edit.xhtml">
           <ui:define name="label">PName</ui:define>
           <h:inputText id="name" required="true"
                           value="#{regionHome.instance.pname}"/>
      </s:decorate> 
      </rich:panel>
      <h:commandButton id="save" value="Save" action="#{studyHome.persist}" rendered="#{!studyHome.managed}"/>
      </h:form>

      studyHome :
      -----------
      @Name("studyHome")
      public class StudyHome extends EntityHome<Study>
      {............
      -----------
      public String persist(){
           List<QExp> qList = new ArrayList<QExp>();
           qList.add(getQExp());
           initStudy().setQExp(qList);       
           return super.persist();
      }

      public QExp getQExp() {
           QExp quantExp = qExpHome.initQExp();
           quantExp.setRegion(getRegion());     
           return quantExp;
      }

      public List<Region> getRegion() {     
           List<Region> regionList=new ArrayList<Region>();
           Region region = regionHome.initRegion();
           region.setTreatment(getTreatment());     
           regionList.add(region);     
           return regionList;
      }

      Study entity :
      --------------
      @Entity(name = "Study")
      public class Study
          implements Equals, HashCode, ToString
      {......
      protected List<QExp> qExp;

      @JoinTable(.....)
      public List<QExp> getQExp() {
              if (qExp == null) {
                  qExp = new ArrayList<QExp>();
              }
              return this.qExp;
          }

      public void setQExp(List<QExp> qExp) {
              this.qExp = qExp;
      }

      QExp entity :
      ------------------------
      @Entity(name = "QExp")
      public class QExp
          implements Equals, HashCode, ToString
      {........
      protected List<Region> region;

      @OneToMany(cascade = {  CascadeType.ALL })
      @JoinTable(name = "MET_Q_EXP_REGION_J", joinColumns = {
              @JoinColumn(name = "PARENT_QEXP_ID")
          }, inverseJoinColumns = {@JoinColumn(name = "CHILD_REGION_ID") })
      public List<Region> getRegion() {
           if (region == null) {
                region = new ArrayList<Region>();
           }
           return this.region;
      }
      public void setRegion(List<Region> region) {
           this.region = region;
      }

      Region entity :
      ----------------
      public class Region
          implements Equals, HashCode, ToString
      {..........
      protected String pname;
      ...............
      @Basic
      @Column(name = "PNAME")
      public String getPname() {
           return pname;
      }
      public void setPname(String value) {
           this.pname = value;
      }
        • 1. Re: How to submit 2 form fields with same name

          Val Sw wrote on Oct 02, 2008 17:06:


          I am new to seam not sure how to submit 2 form fields with same name, Please suggest, thanks in advance...




          Why?


          We have one form which corresponds to different fields from different entities.




          Well, then use different EL expressions.


          Root is Study entity, which have OneToMany relation to QExp, QExp have OneToMany realtion with Region, all the mapping is fine.



          If there is ONE Region, i.e. one field like Pname, I am able to persist it.



          Issue comes up when we provide multiple form fields with same name for Region, (e.g. if there are 2  Pnames and both have value "#{regionHome.instance.pname}")


          When you write regionHome.instance you are referencing a getInstance method in your regionHome component, and you didn't post the code for that component, but I am guessing it always returns the same object, so, if you set it two times, it makes sense that the last input will overwrite the previous one. (They are both pointing to the setPName in the object returned by getInstance in you regionHome class.


          After clicking Save values for Region 2 (PName) field is only persisted, which somehow overrides Region 1 (PName) field, it should svae both.




          They both refere to the same instance returned by getInstance in you regionHome class. AFAIK getInstance always returns the same instance.


          We have a Entity Region and corresponding regionhome, value for each region form field in xhtml is mapped to regionHome.instance.fieldname





          And if you map it twice to the same field it will write it twice and the last value that it writes will prevail.





          • 2. Re: How to submit 2 form fields with same name
            valatharv
            Thanks for the reply...

            Summary : We created project using seam-gen which gave is CRUD for each new entity.

            Requirement is we need to provide user with all fields on single page.

            As root entity is study, which have OneToMany relation to QExp, QExp have OneToMany realtion with Region, all the mapping is fine.
            There can be multiple Regions which will contain other sub elements.

            Yes, it is correct when we use reagentHome.instance.pname it will always return same instance.

            Even if we map it twice only last value will prevail....

            Is there any workaround....

            Code :
            ---------------------------------------------------
            @Name("regionHome")
            public class RegionHome extends EntityHome<Region>
            {

                @RequestParameter
                Long regionId;
               
                @In(required=false)
                private Long hjid;
               
                @Factory("region")
                public Region initRegion() { return getInstance(); }
               
                @Override
                public Object getId()
                {
                    if (regionId==null)
                    {
                        return super.getId();
                    }
                    else
                    {
                        return regionId;
                    }
                }
               
                @Override @Begin(join=true)
                public void create() {
                    super.create();
                }
            -----------------------------------------------
            @Name("studyHome")
            public class StudyHome extends EntityHome<Study>
            {
                @RequestParameter
                Long studyId;
               
                @In(required=false)
                QExpHome qExpHome;
               
                //@In(required=false)
                @In(create=true)
                RegionHome regionHome;
               
                //@In(required=false)
                @In(create=true)
                TreatmentHome treatmentHome;
               
                @In(required=false)
                TreatmentCompoundHome treatmentCompoundHome;
               
                @In(required=false)
                TreatmentTimeHome treatmentTimeHome;
               
                @In(create=true)   
                ExperimentTableIndexHome experimentTableIndexHome;
               
                @In(create=true)
                public QExp qExp;
               
                @Factory("study")
                public Study initStudy() { return getInstance(); }
               
                @Override
                public Object getId()
                {
                    if (studyId==null)
                    {
                        return super.getId();
                    }
                    else
                    {
                        return studyId;
                    }
                }
               
                @Override @Begin(nested=true)
                public void create() {
                    super.create();
                }
               
                public String persist(){
                     List<QExp> quantList = new ArrayList<QExp>();
                     quantList.add(getQExp());
                    initStudy().setQExp(quantList);       
                    return super.persist();
                }
               
                public QExp getQExp() {
                     QExp quantExp = qExpHome.initQExp();
                     quantExp.setRegion(getRegion());
                      return quantExp;
                 }
               
                public List<Region> getRegion() {
                     List<Region> regionList=new ArrayList<Region>();
                     Region region = regionHome.initRegion();         
                     region.setTreatment(getTreatment());
                     regionList.add(region);         
                     return regionList;
                }
               
                public Treatment getTreatment() {
                      Treatment treatment = treatmentHome.initTreatment();
                      List<TreatmentCompound> treatmentCompoundList = new ArrayList<TreatmentCompound>();
                      treatmentCompoundList.add(treatmentCompoundHome.initTreatmentCompound());
                      treatment.setTreatmentCompound(treatmentCompoundList);
                      treatment.setTreatmentTime(treatmentTimeHome.initTreatmentTime());
                      return treatment;
                 }
            }
            • 3. Re: How to submit 2 form fields with same name

              Val Sw wrote on Oct 02, 2008 18:15:


              Thanks for the reply...

              Summary : We created project using seam-gen which gave is CRUD for each new entity.



              Requirement is we need to provide user with all fields on single page.




              That is fine.


              As root entity is study, which have OneToMany relation to QExp, QExp have OneToMany realtion with Region, all the mapping is fine.
              There can be multiple Regions which will contain other sub elements.




              But if they are OneToMany there could be a thousand QExp for each study and there could be thousands of Regions fore each QExp, and therefore millions of Regions for each Study... are you sure that having all this in the same form is the way to go? (Or are those OneToMany relationship limited on their cardinality?)


              Yes, it is correct when we use reagentHome.instance.pname it will always return same instance.



              Even if we map it twice only last value will prevail....




              It is setting the value the same instance, it is doing what you are asking it to do.


              Is there any workaround....





              Well, you could add a getInstance2 method to your regionHome that returns a different region (but that will only work if there can only be 2 regions). Or you could combine your form with an a4j:repeat and bind it to a method in your regionHome that returns an array full of Region objects.






              • 4. Re: How to submit 2 form fields with same name

                You may find this example very helpful

                • 5. Re: How to submit 2 form fields with same name
                  valatharv

                  Thanks Francisco...


                  I will try to check this, not sure if will it create multiple instances of region fields then on finally clicking Save it should persist all in one go...

                  • 6. Re: How to submit 2 form fields with same name

                    Hibernate does support the notion of entities becoming persistent when referenced by another persistent object.


                    Therefore if all the objects are connected, and the cascades are configured correctly in your @OneToMany and @ManyToOne annotations, all you will have to do is call persistfor you root instance and everything will get saved in one go.

                    • 7. Re: How to submit 2 form fields with same name
                      valatharv
                      Yes, Mapping seems to be fine as when I use JAXB & Hibernate and persist the root element, it automatically persists all the relational tables.

                      Our issue came up when we tried to add multiple fields for reagent on main study.xhtml.

                      Mapping :
                      Root Entity :
                      ----------------------------------
                      @Entity(name = "Study")
                      public class Study implements Equals, HashCode, ToString
                      {
                           ........
                           protected List<QuantExperiment> quantExperiment;

                           @OneToMany(cascade = {CascadeType.ALL})
                          @JoinTable(name = "STUDY_QUANT_EXPERIMENT_J", joinColumns = {
                              @JoinColumn(name = "PARENT_STUDY_ID")
                          }, inverseJoinColumns = {@JoinColumn(name = "CHILD_QUANTEXPERIMENT_ID")})
                          @OrderBy
                          public List<QuantExperiment> getQuantExperiment() {
                              if (quantExperiment == null) {
                                  quantExperiment = new ArrayList<QuantExperiment>();
                              }
                              return this.quantExperiment;
                          }

                           public void setQuantExperiment(List<QuantExperiment> quantExperiment) {
                              this.quantExperiment = quantExperiment;
                          }
                      ------------------------------------
                      @Entity(name = "QuantExperiment")
                      public class QuantExperiment implements Equals, HashCode, ToString
                      {
                           ........
                           protected List<Reagent> reagent;
                           
                           @OneToMany(cascade = {CascadeType.ALL})
                          @JoinTable(name = "QUANT_EXPERIMENT_REAGENT_J", joinColumns = {
                              @JoinColumn(name = "PARENT_QUANTEXPERIMENT_ID")
                          }, inverseJoinColumns = {@JoinColumn(name = "CHILD_REAGENT_ID")})
                          @OrderBy
                          public List<Reagent> getReagent() {
                              if (reagent == null) {
                                  reagent = new ArrayList<Reagent>();
                              }
                              return this.reagent;
                          }
                      ------------------------------------
                      @Entity(name = "Reagent")
                      public class Reagent    implements Equals, HashCode, ToString
                      {
                           .........
                           protected Treatment treatment;
                           ... so on

                      • 8. Re: How to submit 2 form fields with same name
                        valatharv

                        Also answer to your query...


                        But if they are OneToMany there could be a thousand QExp for each study and there could be thousands of Regions fore each QExp, and therefore millions of Regions for each Study... are you sure that having all this in the same form is the way to go? (Or are those OneToMany relationship limited on their cardinality?)


                        There will be only one QuantExperiment for each Study, and Reagents can be maximum say 15 or so...