1 2 Previous Next 15 Replies Latest reply on Oct 6, 2008 9:46 PM by Val Sw

    Query multiple entities and display on single page

    Val Sw Expert
      I have a page study.xhtml which have form field from different entities.

      When we click on Studylist and click on any created study, the study.xhtml form is displayed which contains study deatils but not other entity QuantExperiment details,
      is it because StudyList.getEjbql() only queries study. I tried changing it but ..:(, please suggest what i am doing wrong...

      study.xhtml
      <rich:panel>
           <f:facet name="header">Study</f:facet>

           <s:decorate id="studyIdDecoration" template="layout/edit.xhtml">
                <ui:define name="label">Study Id</ui:define>
                <h:inputText id="name" required="true"
                                value="#{studyHome.instance.studyId}"/>
           </s:decorate>
           
           <s:decorate id="studyNameDecoration" template="layout/edit.xhtml">
                <ui:define name="label">Study Name</ui:define>
                <h:inputText id="name" required="true"
                                value="#{studyHome.instance.studyName}"/>
           </s:decorate>           
           <div style="clear:both"/>           
      </rich:panel>

      <rich:panel>
           <f:facet name="header">Quant Experiment</f:facet>        
           
           <s:decorate id="entryPointDecoration" template="layout/edit.xhtml">
                <ui:define name="label">Entry Point</ui:define>
                <h:inputText id="name" required="true"
                                value="#{quantExperimentHome.instance.entryPoint}"
                                label="#{quantExperimentHome.instance.entryPoint}"/>
           </s:decorate>
           
            <s:decorate id="affinityCompoundDecoration" template="layout/edit.xhtml">
                <ui:define name="label">Affinity Compound</ui:define>
                <h:inputText id="name" required="true"
                                value="#{quantExperimentHome.instance.affinityCompound}"/>
           </s:decorate>
           ..... so on
      </rich:panel>

      @Name("studyList")
      public class StudyList extends EntityQuery
      {
           @In(required=false)
           QuantExperimentList quantExperimentList;
           
           @In(create=true)
          public QuantExperiment quantExperiment;
           
          @Override
          public String getEjbql()
          {
              return "select study from Study study";       
              //return "select study,quantExperiment from Study study, QuantExperiment quantExperiment";
          }
      }
        • 1. Re: Query multiple entities and display on single page
          Andy Gibson Novice

          Hey Val,


          How is the quantExperimentHome being set up? You don't need to worry about the study list fetching the other entities, your experiment home is able to fetch  the necessary entity if it is told what it is looking for. The question is for a given study, how does the quantExperimentHome bean know which experiment to fetch? I'm not sure of the relationship between the study and the experiment.
          Regardless, it doesn't look like the experiment needs to be returned in the study list, if you can fetch it independently from the quantExperimentHome.

          • 2. Re: Query multiple entities and display on single page
            Val Sw Expert
            Thanks for the reply Andy...

            study.xhtml is the root entity, we need to display form fields of quantExperiment, when user clicks Already created study link from StudyList.
            After clicking the link study.xhtml is displayed and have valid values in study fields e.g. studyHome.instance.studyName is fine but "quantExperimentHome.instance.entryPoint" is null.

            On the other hand when we click Save after filling study and quant experiment fields, page is rendered and values are populated in Quant Experiment fields also...

            study.xhtml
            <s:decorate id="studyNameDecoration" template="layout/edit.xhtml">
            <ui:define name="label">Study Name</ui:define>
            <h:inputText id="name" required="true"
                  value="#{studyHome.instance.studyName}"/>
            </s:decorate>

            <s:decorate id="entryPointDecoration" template="layout/edit.xhtml">
            <ui:define name="label">Entry Point</ui:define>
            <h:inputText id="name" required="true"
                 value="#{quantExperimentHome.instance.entryPoint}"
                 label="#{quantExperimentHome.instance.entryPoint}"/>
            </s:decorate>


            @Name("studyHome")
            public class StudyHome extends EntityHome<Study>
            {
                 ......
                 @In(required=false)
                QuantExperimentHome quantExperimentHome;
                 public String persist(){
                     List<QuantExperiment> quantList = new ArrayList<QuantExperiment>();
                     quantList.add(getQuantExperiment());
                    initStudy().setQuantExperiment(quantList);       
                    return super.persist();
                }
               
                public QuantExperiment getQuantExperiment() {
                     QuantExperiment quantExp = quantExperimentHome.initQuantExperiment();
                     quantExp.setReagent(getReagent());
                      return quantExp;
                 }
            --------------------------------------
            @Name("quantExperimentHome")
            public class QuantExperimentHome extends EntityHome<QuantExperiment>
            {
                 ......
                 @Factory("quantExperiment")
                public QuantExperiment initQuantExperiment() { return getInstance(); }   
                @Override
                public Object getId()
                {
                    if (quantExperimentId==null)
                    {
                        return super.getId();
                    }
                    else
                    {
                        return quantExperimentId;
                    }
                }
               
                @Override @Begin(nested=true)
                public void create() {
                    super.create();
                }

            -----------Entities-------------------
            @Entity(name = "Study")
            @Table(name = "STUDY")
            public class Study
                implements Equals, HashCode, ToString
            {
                 ...
                 protected List<QuantExperiment> quantExperiment;
                 @OneToMany(cascade = {CascadeType.ALL})
                @JoinTable(name = "STUDY_QUANT_EXPERIMENT_JOIN", 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;
                }
                 ...........
            --------------------------------------
            @Entity(name = "QuantExperiment")
            @Table(name = "QUANT_EXPERIMENT")
            public class QuantExperiment
                implements Equals, HashCode, ToString
            {
                 ...
                 protected String entryPoint;
                 .....
                 @Basic
                @Column(name = "ENTRYPOINT")
                public String getEntryPoint() {
                    return entryPoint;
                }
                 .......
            • 4. Re: Query multiple entities and display on single page
              Andy Gibson Novice

              Yes, I think so, I think the problem is that the Id for the experiment home bean is not being set up, and thus it is creating a new experiment and when you save it, you are creating a new one and it is redisplaying.


              It all goes back to how you are choosing which experiment to display for a given study. A Study has multiple (one to many) experiments, while the experiment home bean can only display one experiment. So my question is when you display a particular study, how do you determine which experiment is displayed given that a study has multiple experiments. The experiment home bean needs an experiment Id to use as the id of the experiement to load.


              Otherwise, if the id is not defined then the experiment home bean creates a new experiment (which it puts in experiementHome.instance) which is the one you are editing and persisting which is why it stays there when you save the study.


              Cheers,


              Andy Gibson

              • 5. Re: Query multiple entities and display on single page
                Val Sw Expert
                Thanks Andy for replying. Though we have QuantExperiment as list but we will always have one experiment associated to Study.

                Study.java
                @OneToMany(cascade = {CascadeType.ALL})
                @JoinTable(name = "STUDY_QUANT_EXPERIMENT_JOIN", 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;
                }
                .....

                We can get study id using "study.hjid", Is there a way I can change in studyHome or study.xhtml or anywhere ... so that that fields are populated when user clicks on ALREADY created study.
                • 6. Re: Query multiple entities and display on single page
                  Andy Gibson Novice

                  Are you saying that study/experiment relationship is a one-to-one relationship even though it is implemented in a (possibly) many-many table, and returned as a list with one item?


                  If so, why not just add a method to study.java as follows :




                  public QuantExperiment getExperiment() {
                    if (quantExperiment.size() == 0) return null
                    else return quantExperiment.get(0);
                  }





                  In your JSF page, you can then refer to #{studyHome.instance.experiment} to get the experiment.


                  I'm still not sure I'm clear on how you are picking which experiment to display on the study page unless you are using a one-to-one relationship mapped by a table and returned in a list. Unless it is for legacy reasons it seems a little odd compared to having a study Id in the experiment table.










                  • 7. Re: Query multiple entities and display on single page
                    Val Sw Expert
                    Thanks Andy for looking into it....

                    If I add this in study.java,do I need to change anything in studyHome, will these "quantExperimentHome.instance.entryPoint", etc.. values take care of it...

                    public QuantExperiment getExperiment() {
                      if (quantExperiment.size() == 0) return null
                      else return quantExperiment.get(0);
                    }

                    Tables :
                    QUANT_EXPERIMENT table
                         HJID (This is QuantExperiment id)
                             Entry point... etc cols
                    STUDY  table
                         HJID (This is Study id)
                             Name ... etc columns

                    One Study will always One QuantExperiment
                    STUDY_QUANT_EXPERIMENT_J table
                         PARENT_STUDY_ID
                         CHILD_QUANTEXPERIMENT_ID

                    I don't know how to attach screen-shot of browser, but this is what studylist.xhtml screen looks like
                    ===============================
                    ApplicationName:  StudyList   Login

                    studyList
                    ---------
                    StudyId      StudyName (these are headers )
                    1      Study Name Test (this is link which user clicks)
                    ===============================

                    As soon as user clicks the above link, main study.xhtml link opens and related value of study name is populated in h:inputText(studyHome.instance.studyName)
                    For Quant experiment fields we are using "quantExperimentHome.instance.entryPoint". so on...

                    study.xhtml
                    <s:decorate id="studyNameDecoration" template="layout/edit.xhtml">
                         <ui:define name="label">Study Name</ui:define>
                         <h:inputText id="name" required="true"
                                         value="#{studyHome.instance.studyName}"/>
                    </s:decorate>

                    <s:decorate id="entryPointDecoration" template="layout/edit.xhtml">
                         <ui:define name="label">Entry Point</ui:define>
                         <h:inputText id="name" required="true"
                                         value="#{quantExperimentHome.instance.entryPoint}"/>
                    </s:decorate>

                    <s:decorate id="affinityCompoundDecoration" template="layout/edit.xhtml">
                         <ui:define name="label">Affinity Compound</ui:define>
                         <h:inputText id="name" required="true"
                                         value="#{quantExperimentHome.instance.affinityCompound}"/>
                    </s:decorate>

                    studyHome.java
                    --------------
                    studyHome.java
                    @Name("studyHome")
                    public class StudyHome extends EntityHome<Study>
                    {

                        @RequestParameter
                        Long studyId;
                      
                        @In(required=false)
                        QuantExperimentHome quantExperimentHome;
                       
                        @In(create=true)
                        ReagentHome reagentHome;
                       
                        @In(create=true)
                        TreatmentHome treatmentHome;
                       
                        @In(required=false)
                        TreatmentCompoundHome treatmentCompoundHome;
                       
                        @In(required=false)
                        TreatmentTimeHome treatmentTimeHome;
                       
                        @In(create=true)   
                        ExperimentTableIndexHome experimentTableIndexHome;
                       
                        @In(create=true)
                        public QuantExperiment quantExperiment;
                       
                        @Factory("study")
                        public Study initStudy() { return getInstance(); }
                       
                        @Override
                        public Object getId()
                        {
                            if (studyId==null)
                            {
                                return super.getId();
                            }
                            else
                            {
                                return studyId;
                            }
                        }
                       
                        @Override @Begin(nested=true)//@Begin(join=true)
                        public void create() {
                            super.create();
                        }
                       
                        public String persist(){
                             List<QuantExperiment> quantList = new ArrayList<QuantExperiment>();
                             quantList.add(getQuantExperiment());
                            initStudy().setQuantExperiment(quantList);       
                            return super.persist();
                        }
                       
                        public QuantExperiment getQuantExperiment() {
                             QuantExperiment quantExp = quantExperimentHome.initQuantExperiment();         
                             quantExp.setReagent(getReagent());          
                              //Adding Experiment table details
                              quantExp.setExperimentName(quantExperiment.getExperimentTableIndex().getExperimentName());
                              return quantExp;
                         }
                       
                        public List<Reagent> getReagent() {
                             List<Reagent> reagentList=new ArrayList<Reagent>();
                             Reagent reagent = reagentHome.initReagent();         
                             reagent.setTreatment(getTreatment());
                             reagentList.add(reagent);         
                             return reagentList;
                        }
                       
                        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;
                         }
                    • 9. Re: Query multiple entities and display on single page
                      Andy Gibson Novice

                      Is there a reason you are keeping the experiments as a list in the study entity instead of a single reference to the experiment to the study? You can do it this way, it's just fairly unorthodox and hard to decipher looking at it.


                      For such a one to one mapping, you could just add a column to the study table referencing the experiment and using  :


                      Study.java


                      @OneToOne
                      @JoinColumn(name="Experiment_id")
                      private Experiment experiment = new Experiment();
                      ...
                      
                      public getter / setter experiment()
                      


                      This will put an experiment property on your study class. In your jsf code,  You can just write :


                      <h:outputText value="#{study.studyname}"/>
                      <h:outputText value="#{study.experiment.entryPoint}"/>



                      If you still want to use a list for whatever reason, then yes, you can just dowhat I wrote before, query the list and just get the first item as the experiment. In such a scenario, you can still use the JSF syntax I wrote above to access the information.


                      There's a lot of weird stuff going on in the code  you posted, like the getQuantExperiment where instead of just returning something you are creating new objects each time it is called (JSF will probably call this multiple times if bound up to a page).
                      When you persist the Study, you are setting the experiment by getting it from experimentHome.initExperiment, since I don't think you set up the experiment Id in the experiment home bean, then it will just return a new one.


                      Here's some food for thought :


                      In the study Home bean, you have the study id to load the study from. If the experiment is part of your study entity, it will automatically get loaded as needed with the study. If you are creating a new study, then set it up initially when the study is created (I think it is in the initInstance method which you can override in the home bean). You don't need to inject all those home beans  because the data you need is probably already part of your model since it all appears to be one to one (even if it is held in lists). Either way, those home beans don't appear to be initialized with an id to load from, so all they are doing is creating new instances, which you can do with a new() statement and no need for injecting them.


                      Cheers,


                      Andy Gibson


                      • 10. Re: Query multiple entities and display on single page
                        Val Sw Expert

                        Thanks a lot Andy for guidance.... I understand that I need to clean-up the stuff, I will follow your suggestion and will update you soon...

                        • 11. Re: Query multiple entities and display on single page
                          Val Sw Expert
                          Hi Andy,

                          I am working on your suggestion, please check and help..

                          a) We would still want to use Experiment as a list though there will be always one Experiment as of now.

                          b) Experiment is part of my study entity. Relationship between study and experiment is stored in Join table
                          ---------------------------------
                          @OneToMany(cascade = {CascadeType.ALL})
                          @JoinTable(name = "MET_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;
                          }
                          ---------------------------------
                          I am very much new to this, I need your help to make studyHome proper, removing the weird code, moving slowly....

                          c) When we click "Save" from main study.xhtml, it calls studyHome.persist,
                          which then calls getQuantExperiment() to set QuantExperiment in study,
                          getQuantExperiment() calls getReagent() and sets Reagent in QuantExperiment
                          Similarly getReagentCalls() calls getTreatment() to set Traetments....

                          I am very much new to this, I need your help to make studyHome proper, removing the weird code, for the best approach:
                          -Should I create getQuantExperiment(), getReagent(), getTreatment in respective homes i.e. quantExperimentHome, reagentHome, treatmentHome..... OR it is fine in studyHome.java itself. Existing code persists all the realtions properly...

                          -getQuantExperiment()
                          There's a lot of weird stuff going on in the code you posted, like the getQuantExperiment where instead of just returning something you are creating new objects each time it is called (JSF will probably call this multiple times if bound up to a page). When you persist the Study, you are setting the experiment by getting it from experimentHome.initExperiment, since I don't think you set up the experiment Id in the experiment home bean, then it will just return a new one.

                          What is the best way to handle this and what should I change... please highlight the lines which should be corrected...

                          QuantExperiment quantExp = quantExperimentHome.initQuantExperiment();
                          quantExp.setReagent(getReagent());

                          studyHome.java
                          --------------
                          public String persist(){
                               List<QuantExperiment> quantList = new ArrayList<QuantExperiment>();
                               quantList.add(getQuantExperiment());
                               initStudy().setQuantExperiment(quantList);       
                               return super.persist();
                          }

                          public QuantExperiment getQuantExperiment() {
                               QuantExperiment quantExp = quantExperimentHome.initQuantExperiment();
                               quantExp.setReagent(getReagent());
                               //Adding Experimentdetails in QuantExperiment from ExperimentTableIndex
                               quantExp.setExperimentName(quantExperiment.getExperimentTableIndex().getExperimentName());
                               quantExp.setExperimentTableName(quantExperiment.getExperimentTableIndex().getExperimentTableName());
                               ......
                               return quantExp;
                          }

                          public List<Reagent> getReagent() {
                               List<Reagent> reagentList=new ArrayList<Reagent>();
                               Reagent reagent = reagentHome.initReagent();         
                               System.out.println("StudyHome.getReagent(), reagent.getPname() == > "+reagent.getPname());
                               reagent.setTreatment(getTreatment());
                               reagentList.add(reagent);         
                               System.out.println("StudyHome.getReagent(), reagentList == > "+reagentList.size());
                               return reagentList;
                          }

                          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;
                          }
                          • 12. Re: Query multiple entities and display on single page
                            Andy Gibson Novice

                            I would get things working in stages as you are fairly new to Seam. Start  by getting the studyHome working so you can create and edit studies.


                            @Name("studyHome")
                            @Scope(ScopeType.Conversation)
                            public class StudyHome extends EntityHome<Study> {
                            
                              public Long getStudyId() {
                                return (Long)getId();
                              }
                            
                              public void setStudyId(Long studyId) {
                                  setId(studyId);
                              }
                            
                              @Factory("study")
                              public Study getStudy() {
                                return getInstance();
                              }
                            
                            }



                            If there is no study Id, then a new study is created, the model should take care of initializing the experiments list.


                            i.e. Study.java


                            public class Study {
                              public Study() {
                                 super();
                                 setExperiments(new ArrayList<Experiment>());
                              }
                            }




                            In pages.xml, for the study page, add the following :


                            <page view-id="studyEdit.xhtml">
                                <param name="studyId" value="#{studyHome.studyId}"/>
                            </page>
                            


                            Using parameters in pages.xml is more robust than the @RequestParam annotation. Using pages.xml lets parameters pass through when you get a redirect to login.  You can however use the RequestParams annotation, you just need to override the getId method to return the Id.


                            (Incidentally, you override on GetId can cause problems since the request  parameter annotation will be null on subsequent calls and you don't set the id from the parameter. You need to call SetId(studyId) somewhere in your getId method if it is not already set and you are using the parameter value).


                            This home bean can be used to create new studies or edit existing ones and the syntax for the JSF is the same as the one I showed you.  #{study.name} or #{study.experiment.entryPoint}.
                            When you enter the page with a study Id,  the page will request a study instance which will go to the factory. The studyHome bean is created, the parameter is put into the home bean studyId property, the factory method is called and study is loaded based on the id.
                            In your page, you refer to study.experiment which will lazy load the experiment.


                            This should take care of handling the study and experiment. You should initialize the reagent and treatments for new instance in the model construction, You don't need home beans because they just construct it for you just by calling new().


                            Cheers,


                            Andy





                            • 13. Re: Query multiple entities and display on single page
                              Andy Gibson Novice

                              Actually, that study code needs to add a new experiment and should be :


                              public class Study {
                                public Study() {
                                   super();
                                   setExperiments(new ArrayList<Experiment>());
                                   getExperiments().add(new Experiment());
                                }
                              }



                              Cheers,


                              Andy

                              • 14. Re: Query multiple entities and display on single page
                                Val Sw Expert
                                Hi Andy,

                                Following your suggestion, to display QuantExperiment details also, when user clicks ALREADY created study.

                                a) I have added the code in study.java as mentioned above and able to create and edit Study.
                                b) Note, we have id as hjid for Study and QuantExperiment entity.
                                c) Do we need to create studyEdit.xhtml also?

                                Now, as per requirement, we would like to add QauntExperiment details in the main Study.xhtml.
                                What should be my next step so that we create Study & quant Experiment in one go and also when we click ALREADY created study, it should display both entity fields.


                                quantexperiment fileds....
                                <s:decorate id="entryPointDecoration" template="layout/edit.xhtml">
                                     <ui:define name="label">Entry Point</ui:define>
                                     <h:inputText id="name" required="true"
                                          value="#{quantExperimentHome.instance.entryPoint}"/>
                                </s:decorate>

                                <s:decorate id="affinityCompoundDecoration" template="layout/edit.xhtml">
                                <ui:define name="label">Affinity Compound</ui:define>
                                <h:inputText id="name" required="true"
                                          value="#{quantExperimentHome.instance.affinityCompound}"/>
                                </s:decorate>
                                .... so on

                                --------------
                                studyHome.java
                                --------------
                                public class Study....{
                                  protected Long hjid;
                                  ........

                                  public Study() {
                                     super();
                                     setQuantExperiment(new ArrayList<QuantExperiment>());
                                     getQuantExperiment().add(new QuantExperiment());
                                  }

                                @OneToMany(fetch=FetchType.EAGER, cascade = {CascadeType.ALL})
                                @JoinTable(name = "MET_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;
                                }

                                -----------
                                study.xhtml
                                -----------
                                <s:decorate id="studyIdDecoration" template="layout/edit.xhtml">
                                     <ui:define name="label">Study Id</ui:define>
                                     <h:inputText id="name" required="true"
                                          value="#{studyHome.instance.studyId}"/>
                                </s:decorate>
                                <s:decorate id="studyNameDecoration" template="layout/edit.xhtml">
                                     <ui:define name="label">Study Name</ui:define>
                                     <h:inputText id="name" required="true"
                                          value="#{studyHome.instance.studyName}"/>
                                </s:decorate>

                                --------------------
                                QuantExperiment.java
                                --------------------
                                @Entity(name = "QuantExperiment")
                                protected Long hjid;
                                .........
                                @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="MET_QUANT_EXPERIMENT_STORE")
                                @Column(name = "HJID")
                                public Long getHjid() {
                                     return hjid;
                                }
                                public void setHjid(Long value) {
                                     this.hjid = value;
                                }
                                1 2 Previous Next