13 Replies Latest reply on Oct 1, 2010 6:35 AM by Leo van den berg

    How to use joined sets

    Dan Dosch Newbie

      Here is my entity bean. It has a forgein key which is a one-to-many relationship with the kittens table


      
      public class Cat implements java.io.Serializable {
      
      
           private BigDecimal catId;
      
           private String catName;
      
           private Set<Kitten> kittens = new HashSet<Kitten>(0);     
      
           .
      
           .
      
           .
      
      }





      I have an action bean that does a join fetch to get


      
      @Factory("theCats")
      
      public void displayCats() {
      
           theCats = em.createQuery("select c from Cats c join fetch c.Kittens").getResultList();
      
      }




      What I would like to be able to do is use a table to display a row that has the Cat's name once, and then the properties of the Kittens in a list as a second column:




      
      <rich:dataTable var="cats"
      
                 value="#{theCats}"
      
              rendered="#{theCats.rowCount>0}">
      
      <h:column>
      
          <f:facet name="header">
      
           <h:outputText value="Name" />
      
          </f:facet>
      
          #{theCats.catName}
      
      </h:column>              
      
      <h:column>
      
          <f:facet name="header">
      
           <h:outputText value="Kittens" />
      
          </f:facet>
      
          
      
          ######## Here is where I want to display all kittens, as a list inside this table #######
      
          
      
      </h:column>
      
      </rich:dataTable>




      I have tried the following but it gave me an error


      
      Property 'kittenName' not found on type org.hibernate.collection.PersistentSet



      
      <rich:dataTable var="cats"
      
                 value="#{theCats}"
      
              rendered="#{theCats.rowCount>0}">
      
      <h:column>
      
          <f:facet name="header">
      
           <h:outputText value="Name" />
      
          </f:facet>
      
          #{theCats.catName}
      
      </h:column>
      
      <h:column>
      
          <f:facet name="header">
      
           <h:outputText value="Kittens" />
      
          </f:facet>
      
          <rich:dataList var="theCatsKittens"
      
                 value="#{theCats.kittens}"
      
                  rows="1">
      
            <h:outputText value="#{theCatsKittens.kittenName}" />
      
          </rich:dataList>
      
      </h:column>
      
      </rich:dataTable>




      How can I use the

      Set<Kitten>

      in this context?


      Thanks,
      Dan

        • 1. Re: How to use joined sets
          Dan Dosch Newbie

          Incase it isn't clear, I am basically trying to have a table that looks like this


          
          +------------------------+
          
          |Cat1Name | Kitten1Name  |
          
          |         | Kitten2Name  |
          
          |         | Kitten3Name  |
          
          |------------------------+
          
          |Cat2Name | Kitten1Name  |
          
          |         | Kitten2Name  |
          
          |------------------------+
          
          |Cat3Name | Kitten1Name  |
          
          |         | Kitten2Name  |
          
          |         | Kitten3Name  |
          
          |         | Kitten4Name  |
          
          |         | Kitten5Name  |
          
          |------------------------+
          
          |Cat4Name | Kitten1Name  |
          
          |------------------------+

          • 2. Re: How to use joined sets
            Kenneth Christensen Novice

            Try this one:


            public class Cat implements java.io.Serializable {
            
                 private BigDecimal catId;
                 private String catName;
                 private Set<Kitten> kittens = new HashSet<Kitten>(0);     
                 .
                 .
                 .
            
                   @Transient
                   public List<Kitten> getKittensList() {
                       return new ArrayList<Kitten>(kittens);
                   }
            
            }



            <rich:dataTable var="cats"
                       value="#{theCats}"
                    rendered="#{theCats.rowCount>0}">
            <h:column>
                <f:facet name="header">
                 <h:outputText value="Name" />
                </f:facet>
                #{theCats.catName}
            </h:column>
            <h:column>
                <f:facet name="header">
                 <h:outputText value="Kittens" />
                </f:facet>
                <rich:dataList var="theCatsKittens"
                       value="#{cats.kittensList}"
                        rows="1">
                     <h:column>
                      <h:outputText value="#{theCatsKittens.kittenName}" />
                     </h:column>
                </rich:dataList>
            </h:column>
            </rich:dataTable>

            • 3. Re: How to use joined sets
              Dan Dosch Newbie

              Using the @Transient allows me to use the set as a List which is nice.


              The only problem now is that instead of


              
              +------------------------+
              
              |Cat1Name | Kitten1Name  |
              
              |         | Kitten2Name  |
              
              |         | Kitten3Name  |
              
              |------------------------+
              
              |Cat2Name | Kitten1Name  |
              
              |         | Kitten2Name  |
              
              |------------------------+
              
              |Cat3Name | Kitten1Name  |
              
              |         | Kitten2Name  |
              
              |         | Kitten3Name  |
              
              |         | Kitten4Name  |
              
              |         | Kitten5Name  |
              
              |------------------------+
              
              |Cat4Name | Kitten1Name  |
              
              |------------------------+
              
              



              it displays


              
              +------------------------+
              
              |Cat1Name | Kitten1Name  |
              
              +------------------------+
              
              |Cat1Name | Kitten2Name  |
              
              +------------------------+
              
              |Cat1Name | Kitten3Name  |
              
              |------------------------+
              
              |Cat2Name | Kitten1Name  |
              
              +------------------------+
              
              |Cat2Name | Kitten2Name  |
              
              |------------------------+
              
              |Cat3Name | Kitten1Name  |
              
              +------------------------+
              
              |Cat3Name | Kitten2Name  |
              
              +------------------------+
              
              |Cat3Name | Kitten3Name  |
              
              +------------------------+
              
              |Cat3Name | Kitten4Name  |
              
              +------------------------+
              
              |Cat3Name | Kitten5Name  |
              
              |------------------------+
              
              |Cat4Name | Kitten1Name  |
              
              |------------------------+
              
              



              Does Rich Faces support objects inside of objects? (ie a dataList inside of a dataTable)


              Thanks,
              Dan

              • 4. Re: How to use joined sets
                Kenneth Christensen Novice

                Maybe you should try to remove the row limit:


                <rich:dataList var="theCatsKittens"
                           value="#{cats.kittensList}"
                            rows="1"> <!----- REMOVE
                         <h:column>
                          <h:outputText value="#{theCatsKittens.kittenName}" />
                         </h:column>
                    </rich:dataList>
                




                Does Rich Faces support objects inside of objects? (ie a dataList inside of a dataTable)

                Yes, it works for me :-)

                • 5. Re: How to use joined sets
                  Dan Dosch Newbie

                  Yep that was it. I cant remember why I added that in the first place.


                  Thanks for the help.


                  • 6. Re: How to use joined sets
                    Deesha Singh Newbie

                    Hi,


                    I was trying to do the same thing and found this convo on the forum. I tried to do it the same way, and it looks ok, but when i open the page the datalist doesn't load the kitten names (to follow the example). I have no idea what I'm doing wrong, but it follows the example above. Any ideas anyone?

                    • 7. Re: How to use joined sets
                      Leo van den berg Master

                      Hi,


                      Have you seen the conversion from Set to List in the above code ? The table-components are not able to work with a Set so that is the reason you have to transform them.


                      If that isn't working, send some code.


                      Leo

                      • 8. Re: How to use joined sets
                        Deesha Singh Newbie

                        Hi Leo,


                        Thanks for replying.


                        Ok I got it to work but it won't do the right thing, I hope you don't mind taking a look through this. Might get long-ish. I'm trying to do the same thing but with devices and device states (on/off). The app will save a device in an entity, then in a seperate entity will start logging its state behaviour (when it turns on/off). I want to show a list of the devices with their current states.


                        Erm, before i post some code, can you please explain how to do it? copy and paste is a bad idea and I'm new here, I dont really know.


                        Sorry about this.

                        • 9. Re: How to use joined sets
                          Leo van den berg Master

                          Hi,


                          The most important thing is to wrap code inside a code block. The way to do that is to paste the code first, select it and use the select box (Format selected text ...) and select Code Block.


                          Please try to be very brief, so only the code with the associations (JPA-annotations) is interesting, and off course the beans behind the pages.


                          Leo

                          • 10. Re: How to use joined sets
                            Deesha Singh Newbie
                            Ok. So my app deals with devices, and i have 2 entity beans (one for the devices, and one for the tracking of their states). So AllEntity has device name and type, and AllDetailEntity has state(on/off) and power comsumption etc. There's a @ManyToOne mapping between the two, because the database stores each entry of a change in the state (for logging purposes) and there's a timestamp to keep track of when things happened.

                            What I want is to display a list of the devices with their current state next to them. I did everything above with this:



                            `public void newList()
                                 {
                                      devicesList = entityManager.createQuery("Select a from AllEntity a order by type desc").getResultList();

                                      for (int i = 0; i < devicesList.size(); i++)
                                           {
                                           log.info("Started3 ");
                                           device = devicesList.get(i);
                                           AllDetailEntity currentDetailEntity = (AllDetailEntity) entityManager.createQuery("select detail from AllDetailEntity detail where detail.detailId.id=:id order by datetime desc")
                                                                                                  .setParameter("id", device.id).setMaxResults(1).getSingleResult();
                                           log.info("Adding to list");
                                           AllEntity.statesList.add(currentDetailEntity);
                                           System.out.println("System state: " + currentDetailEntity.getState());
                                           }
                                 }`

                            That creates the 'kittenList' (now statesList) above with only the relevant state info. Everything else is the same as the code above, but what im getting is:



                            `Device Type     Device Location        Appliance     Device State
                            Pool Heater     Back Patio                     on
                                                                               on
                                                                               on
                                                                               on
                            Plug Point     Kitchen                Freezer        on
                                                                               on
                                                                               on
                                                                               on
                            Light             Other Bedroom                        on
                                                                               on
                                                                               on
                                                                               on
                            Geyser             Kitchen                             on
                                                                               on
                                                                               on
                                                                               on
                            `
                            So what its doing is looping the list with each entry instead of putting the relevant state next to each device.

                            Now I've been racking my brain about this display issue and i just cant come up with a solution. Any suggestions would be much appreciated, I know I may be going about this the entirely wrong way.

                            • 11. Re: How to use joined sets
                              Leo van den berg Master

                              Hi,


                              My first reaction is that you should look at Hibernate-Envers to save the previous states of devices. I uee it and it works great.


                              I'll be back after reading your previous text in-depth.


                              Leo

                              • 12. Re: How to use joined sets
                                Deesha Singh Newbie

                                Having a look at the hibernate-envers, sounds good. But basically what i want to do is have two lists displayed on the same page next to each other..It's the easiest solution to what i need, and i can generate the lists just fine, my problem is the display. is it possible or am i wasting my time?

                                • 13. Re: How to use joined sets
                                  Leo van den berg Master

                                  Hi,


                                  I don't think the display you want to create is a problem and it all depends on the query to retrieve your data. So if you only want to have the device with its present status, you should retrieve it with a simple while restriction which gives you the entity with its last state.


                                  What you're doing now is do a query to get the devices and after that a query for each independent state. Besides the unnecessary DB overhead you're creating it is really slow and unneccesary because the DB can do this for you.


                                  First make the association bidirectional between the device and its status. If you then use a naturally sorted Status Set or Status List with an index, you can retrieve the Device and lastStatus in a single query. For instance if you have a timestamp on the status you can use that.


                                  Again, if you do this with Envers you could use just one single entity and include the status. For every update Envers will create the entry in the audittable and that's basically all you have to do.


                                  Leo