5 Replies Latest reply on Jul 8, 2009 4:34 PM by wolfgangknauf

    onetomany relationship question

    lpiccoli

      i read the 'EJB3 relationships' wiki article
      http://www.jboss.org/community/wiki/EJB3relationships and have a question.

      @Entity()
      public class ParentBean implements Serializable
      {
       private Set<ChildBean> listChilds = new HashSet<ChildBean>();
      
       @OneToMany(mappedBy="parent")
       public Set<ChildBean> getChilds()
       {
       return this.listChilds;
       }
      }
      
      @Entity()
      public class ChildBean implements Serializable
      {
       @ManyToOne ()
       public ParentBean getParent()
       {
       return this.parent;
       }
      }
      
      


      Q1. essentially why doesnt the following work

       ParentBean parent = ...;
       ChildBean child1 = ...;
       child1.setParent(parent);
      
       ChildBean child2 = ...;
       child2.setParent(parent);
      
      .....
      
       ParentBean parentBean = this.entityManager.find(ParentBean.class, int_ParentId);
      
      
       assertEquals( 2, parentBean.getChilds().size() ); <--- why do i get 0
      
      


      Q2. Does the parent.setChilds( list) must be called before calling
      parent.getChilds() or can is ok set the relationship with a)child1.setParent(p),
      child2.setParent(p) or b) having the data loaded from scripts?

      currently my parent.getChilds() returns null although there is
      parent/child relationship on the many-to-one table.

      Q3. I was expceting that the parent.getChilds() executes a query like ('from child c where c.parent=:parent' )

      is my understanding of one-to-many relationship wrong?



        • 1. Re: onetomany relationship question
          wolfgangknauf

          Hi,

          Q1: for each child, you have to do this:

          ParentBean parent = ...;
           ChildBean child1 = ...;
          ==> parent.getChilds().add (child1);
           child1.setParent(parent);
          

          Otherwise, the relation will not be saved, but there will be no error message.

          Q2: I don't know what is happening if you call "setChilds" before loading them, but I would expect strange side effects at least when the collection is under EntityManager control (inside a session bean method/transaction). So better manipulate the collection returned by "getChilds" and add/remove items. I will give this a try in the next few days and update my Wiki if I find a "No go".

          Q3: Did you activate SQL query logging in your persistence.xml?
          <?xml version="1.0" encoding="UTF-8"?>
           <persistence xmlns="http://java.sun.com/xml/ns/persistence"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
           version="1.0">
           <persistence-unit name="..">
           ...
           <properties>
           ...
          ===> <property name="hibernate.show_sql" value="true"></property>
           </properties>
           </persistence-unit>
           </persistence>
          

          But I am not sure how the childs are loaded. I will take a look at the JBoss console when I near a computer with JBoss ;-)


          Best regards

          Wolfgang

          • 2. Re: onetomany relationship question
            lpiccoli

            thanks for the rapid response wolfgang.

            i added the SQL tracing but there is *no* SQL when calling parent.getChilds().

            So if i have understood the 'onetoMany' relationship, it doesnt populated the 'many' unless it has been explicitly set using the parent.setChilds().

            This seems an almost pointless relationship.

            In order to get the list of childs from existing data (ie.reference data), one must use a join query like

            em.query( 'from Child child where child.parent_id=:id')
            


            I was hoping the above would be executed during the retrieval of the 'many'.

            Q1. what exactly is the point of the 'onetoMany' if it is only useful if used when explicitly setting the collection on the 'one' side?

            any help to clarify the above is most appreciated.

            -lp

            • 3. Re: onetomany relationship question
              wolfgangknauf

              Hi,

              actually, the "to many" side should be automatically populated when you access it. So, there is no need to perform entity manager queries.

              Depending on the fetchType of the relationship, different things might happen:
              If fetchType is "EAGER", then the children will be loaded when the parent is loaded. In this case, the EntityManager will fire some join statement against the database to load parent and childs with one query.
              If fetchType is "LAZY", then the first call to "parent.getChilds()" will trigger the child collection loading. This will only work if the parent entity is under EntityManager control.

              Hope this helps a bit.

              Wolfgang

              • 4. Re: onetomany relationship question
                lpiccoli

                ok it seems that my test cases were erroneous.

                i finally got the onetomany to fetch the 'many' by refreshing the entity. This then invoked the following query

                hibernate: select childbean0_.ID as ID3_, childbean0_.parent_ID as parent2_3_ from ChildBean childbean0_ where childbean0_.parent_ID=?
                



                my test code also shows that the relationship only needs to be set on the many side.

                
                @Test
                 public void one2manyTestWithSettingManySide() {
                
                 ParentBean parent = new ParentBean();
                 entityManager.persist(parent);
                 long id = parent.getId();
                
                 ChildBean child1 = new ChildBean();
                 child1.setParent(parent);
                 entityManager.persist(child1);
                
                 ChildBean child2 = new ChildBean();
                 child2.setParent(parent);
                 entityManager.persist(child2);
                
                 Query query = entityManager.createQuery("from ChildBean child where parent.id=:id");
                 query.setParameter("id", id);
                 List resultList = query.getResultList();
                 assertEquals( 2, resultList.size() );
                
                 //check refresh
                 entityManager.refresh(parent);
                 assertEquals( 2, parent.getChilds().size() );
                
                 ParentBean parentBean = entityManager.find(ParentBean.class, parent.getId());
                
                 assertEquals( 2, parentBean.getChilds().size() );
                
                 }
                
                


                thanks for your help wolfgang.

                -lp

                • 5. Re: onetomany relationship question
                  wolfgangknauf

                  Hi,

                  I played around with your sample a bit. I agree that it works if you first create and save the parent, then create the child, set the parent and persist the child.
                  But assume that you don't save the parent, but the child. Here is the code snippet:

                  ParentBean parent = new ParentBean();
                   entityManager.persist(parent);
                  
                  
                   ChildBean child1 = new ChildBean();
                   parent.getChilds().add(child1);
                   //child1.setParent(parentNew);
                  
                   entityManager.persist(parent)
                  

                  In this case, child and parent will be saved without error messages, but the relationship related database data is missing.

                  So, as a general guideline: always update both sides of the relationship, this will avoid a lot of problems ;-).

                  Best regards

                  Wolfgang