1 2 Previous Next 17 Replies Latest reply on Nov 9, 2009 11:43 AM by Wolfgang Knauf

    ManyToMany problem

    Sven Kilchenmann Newbie

      Hi all

      playing around with Seam and trying to fill a manytomany join table. Following situation: A person has multiple roles (based on work, not as a role known from the security). A role could have 0..n functions (specialised education). so i tried the follwing:

      Role and Funtion joined on role_function (join table, for the moment only role_id and function_id, in future with a generated id) The qualification table contains person_id and role_function_id.

      Now the questions:

      1) How to autogenerate an role_function_id on assigning a function to a role?
      2) Do i have to develop a seperate bean for the qualification?

      Sorry if the question is clear for all. Searched for the answer and didn't find something which will helps out a newbie like me! Hope someone will clear my questions. Thanks in advance.

        • 1. Re: ManyToMany problem
          Wolfgang Knauf Master

          Hi,

          I assume that you want to use EJB3/JPA for creating your entities?

          In this case, you don't need a role_function entity, and the server will autogenerate the database table for you. The entity "Role" will have a list of "Functions", and the "Function" will have a list of "Role", both connected by annotations.

          Pseudocode:

          @Entity
          public class Role implements Serializable
          {
           @ManyToMany (mappedBy="roles")
           public List<Function> functions;
          }
          
          @Entity
          public class Function implements Serializable
          {
           @ManyToMany ()
           public List<Role> roles;
          }
          


          Then, your code can access the functions of a role by "myRole.functions.get(x);". The rest is the job of the server and you don't have to care much about it.

          Of course, there is quite a bit more to keep in mind. First of all, the two fields should have a getter and setter. More detailed information can be found here: http://www.jboss.org/community/wiki/EJB3relationships

          Hope this helps

          Wolfgang

          • 2. Re: ManyToMany problem
            Sven Kilchenmann Newbie

            Hi Wolfgang

            Thanks for your input.
            So far i got it already. The role_function is generated automaticly

            But now i got
            role_id | function_id

            What should i do if like a generated id within this table?

            Thanks a lot

            • 3. Re: ManyToMany problem
              Wolfgang Knauf Master

              Hi,

              basically, you don't need a generated ID for the mapping table because the pair "role_id/function_id" is already a valid primary key.
              If you need a id column anyway, you have to build a mapping entity with a generated ID property and two @OneToMany relationship fields to Role and Function.

              So your code for mapping a function to a role could be:

              RoleToFunction role2FunctionNew = new RoleToFunction();
              role2FunctionNew.setFunction(...);
              role2FunctionNew.setRole(...);
              
              role.getFunctionmappings().add (role2FunctionNew);
              


              Hope this helps

              Wolfgang

              • 4. Re: ManyToMany problem
                Sven Kilchenmann Newbie

                Hi Wolfgang

                Thanks for your input.
                I need the generated id to reference to this pair (role - function).

                I tried to do it as it is described here:
                http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Additional_columns_in_join_table.

                for the moment it doesn't work. I'll keep going on this way.
                Perhaps i will return a few hours later again with more questions.

                • 5. Re: ManyToMany problem
                  Sven Kilchenmann Newbie

                  Sorry :)

                  I just stuck here and have no idea what the problem is.

                  Hope someone got input for me!

                  Here my classes:

                  package ch.emtm.entity;
                  
                  import java.io.Serializable;
                  import java.util.List;
                  
                  import javax.persistence.Entity;
                  import javax.persistence.GeneratedValue;
                  import javax.persistence.Id;
                  import javax.persistence.JoinColumn;
                  import javax.persistence.OneToMany;
                  import javax.persistence.OneToOne;
                  import javax.persistence.Version;
                  
                  import org.hibernate.validator.Length;
                  import org.hibernate.validator.NotNull;
                  import org.jboss.seam.annotations.Name;
                  
                  @Entity
                  @Name("role")
                  public class Role implements Serializable
                  {
                   /**
                   *
                   */
                   private static final long serialVersionUID = 1L;
                  
                   @Id
                   @GeneratedValue
                   private Long id;
                   @Version
                   private Integer version;
                   @Length(max=64)
                   @NotNull
                   private String name;
                   @OneToMany(mappedBy="role")
                   private List<RoleFunction> functions;
                   @NotNull
                   @OneToOne
                   @JoinColumn(name = "status")
                   private RecordStatus recordStatus = new RecordStatus();
                  
                   /**
                   * @return the id
                   */
                   public Long getId() {
                   return id;
                   }
                   /**
                   * @param id the id to set
                   */
                   public void setId(Long id) {
                   this.id = id;
                   }
                   /**
                   * @return the version
                   */
                   public Integer getVersion() {
                   return version;
                   }
                   /**
                   * @param version the version to set
                   */
                   public void setVersion(Integer version) {
                   this.version = version;
                   }
                   /**
                   * @return the name
                   */
                   public String getName() {
                   return name;
                   }
                   /**
                   * @param name the name to set
                   */
                   public void setName(String name) {
                   this.name = name;
                   }
                   /**
                   * @return the functions
                   */
                   public List<RoleFunction> getFunctions() {
                   return functions;
                   }
                   /**
                   * @param functions the functions to set
                   */
                   public void setFunctions(List<RoleFunction> functions) {
                   this.functions = functions;
                   }
                   /**
                   * @return the recordStatus
                   */
                   public RecordStatus getRecordStatus() {
                   return recordStatus;
                   }
                   /**
                   * @param recordStatus the recordStatus to set
                   */
                   public void setRecordStatus(RecordStatus recordStatus) {
                   this.recordStatus = recordStatus;
                   }
                  
                  }
                  


                  package ch.emtm.entity;
                  
                  import java.io.Serializable;
                  import java.util.ArrayList;
                  import java.util.List;
                  
                  import javax.persistence.Entity;
                  import javax.persistence.GeneratedValue;
                  import javax.persistence.Id;
                  import javax.persistence.JoinColumn;
                  import javax.persistence.OneToMany;
                  import javax.persistence.OneToOne;
                  import javax.persistence.Version;
                  
                  import org.hibernate.validator.Length;
                  import org.hibernate.validator.NotNull;
                  import org.jboss.seam.annotations.Name;
                  
                  @Entity
                  @Name("function")
                  public class Function implements Serializable
                  {
                   /**
                   *
                   */
                   private static final long serialVersionUID = 1L;
                  
                   @Id
                   @GeneratedValue
                   private Long id;
                   @Version
                   private Integer version;
                   @Length(max = 64)
                   @NotNull
                   private String name;
                   @OneToMany(mappedBy="function")
                   private List<RoleFunction> roles = new ArrayList<RoleFunction>();
                   @NotNull
                   @OneToOne
                   @JoinColumn(name = "status")
                   private RecordStatus recordStatus = new RecordStatus();
                  
                   public Long getId() {
                   return id;
                   }
                  
                   public void setId(Long id) {
                   this.id = id;
                   }
                  
                   public Integer getVersion() {
                   return version;
                   }
                  
                   @SuppressWarnings("unused")
                   private void setVersion(Integer version) {
                   this.version = version;
                   }
                  
                   public String getName() {
                   return name;
                   }
                  
                   public void setName(String name) {
                   this.name = name;
                   }
                  
                   /**
                   * @return the roles
                   */
                   public List<RoleFunction> getRoles() {
                   return roles;
                   }
                  
                   /**
                   * @param roles the roles to set
                   */
                   public void setRoles(List<RoleFunction> roles) {
                   this.roles = roles;
                   }
                  
                   /**
                   * @return the recordStatus
                   */
                   public RecordStatus getRecordStatus() {
                   return recordStatus;
                   }
                  
                   /**
                   * @param recordStatus the recordStatus to set
                   */
                   public void setRecordStatus(RecordStatus recordStatus) {
                   this.recordStatus = recordStatus;
                   }
                  
                  }
                  


                  package ch.emtm.entity;
                  
                  import java.io.Serializable;
                  
                  import javax.persistence.Entity;
                  import javax.persistence.GeneratedValue;
                  import javax.persistence.Id;
                  import javax.persistence.ManyToOne;
                  import javax.persistence.PrimaryKeyJoinColumn;
                  
                  import org.jboss.seam.annotations.Name;
                  
                  @Entity
                  @Name("rolefunction")
                  public class RoleFunction implements Serializable
                  {
                   /**
                   *
                   */
                   private static final long serialVersionUID = 1L;
                  
                   @Id
                   @GeneratedValue
                   private Long id;
                   @ManyToOne()
                   @PrimaryKeyJoinColumn(name = "function", referencedColumnName = "id")
                   private Function function = new Function();
                   @ManyToOne()
                   @PrimaryKeyJoinColumn(name = "role", referencedColumnName = "id")
                   private Role role = new Role();
                  // @OneToMany(mappedBy="roleFunction")
                  // private List<Qualification> qualifications = new ArrayList<Qualification>();
                  
                   /**
                   * @return the id
                   */
                   public Long getId() {
                   return id;
                   }
                   /**
                   * @param id the id to set
                   */
                   public void setId(Long id) {
                   this.id = id;
                   }
                   /**
                   * @return the roleId
                   */
                   public Role getRole() {
                   return role;
                   }
                   /**
                   * @param roleId the roleId to set
                   */
                   public void setRole(Role role) {
                   this.role = role;
                   }
                   /**
                   * @return the functionId
                   */
                   public Function getFunction() {
                   return function;
                   }
                   /**
                   * @param functionId the functionId to set
                   */
                   public void setFunction(Function function) {
                   this.function = function;
                   }
                  // /**
                  // * @return the qualifications
                  // */
                  // public List<Qualification> getQualifications() {
                  // return qualifications;
                  // }
                  // /**
                  // * @param qualifications the qualifications to set
                  // */
                  // public void setQualifications(List<Qualification> qualifications) {
                  // this.qualifications = qualifications;
                  // }
                  
                  }
                  


                  So i get an error:

                  21:20:01,733 SEVERE [application] java.lang.NullPointerException
                  javax.faces.el.EvaluationException: java.lang.NullPointerException
                   at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
                   at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
                   at javax.faces.component.UICommand.broadcast(UICommand.java:387)
                   at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321)
                   at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296)
                   at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253)
                   at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466)
                   at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
                   at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
                   at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
                   at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
                   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                   at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:510)
                   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
                   at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
                   at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
                   at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:368)
                   at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:495)
                   at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
                   at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                   at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
                   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                   at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
                   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                   at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
                   at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
                   at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
                   at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
                   at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
                   at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
                   at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
                   at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
                   at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                   at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
                   at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                   at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
                   at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
                   at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
                   at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
                   at java.lang.Thread.run(Thread.java:619)
                  Caused by: java.lang.NullPointerException
                   at ch.emtm.session.RoleHome.update(RoleHome.java:62)
                  


                  • 6. Re: ManyToMany problem
                    Sven Kilchenmann Newbie

                    one step closer :D

                    i got the problem - at least i think i'm close to!
                    on roleList.xhtml i got:

                    <s:decorate id="functionField" template="layout/edit.xhtml">
                    <ui:define name="label">Function</ui:define> <h:selectManyCheckbox id="functions" value="#{roleHome.instance.functions}" layout="pageDirection">
                    <s:selectItems value="#{functionList.resultList}" var="function" label="#{function.name}" />
                    <s:convertEntity />
                    </h:selectManyCheckbox>
                    </s:decorate>


                    and when i save i receive the following error:
                    23:33:05,776 SEVERE [application] java.lang.ClassCastException: ch.emtm.entity.Function cannot be cast to ch.emtm.entity.RoleFunction


                    i understood the problem, but for the moment i have no idea how to solve.
                    i think your code posted above with the new rolefunction() will solve - but i couldn't get.

                    Do you have a hint for me ;)

                    Thanks in advance

                    • 7. Re: ManyToMany problem
                      Sven Kilchenmann Newbie

                      Hi again :D

                      i found a solution - at least i'm close to a solution.

                      I added this function to the Role.

                      @OneToMany(mappedBy="role")
                      private List<RoleFunction> listRoleFunctions;
                      ...
                      public List<Function> getFunctions(){
                       List<Function> functions = new ArrayList<Function>();
                       if(this.listRoleFunctions != null){
                       for(RoleFunction rf:this.listRoleFunctions){
                       Function f = new Function();
                       f = rf.getFunction();
                       functions.add(f);
                       }
                       }
                       return functions;
                       }
                      
                       public void setFunctions(List<Function> functions){
                       if(functions.size() > this.listRoleFunctions.size()){
                       //New function to add
                       for(Function f:functions){
                       boolean add = true;
                       for(RoleFunction roleFunction:this.listRoleFunctions){
                       if(roleFunction.getId().equals(f.getId())){
                       add = false;
                       break;
                       }
                      
                       }
                       if(add){
                       RoleFunction rf = new RoleFunction();
                       rf.setFunction(f);
                       rf.setRole(this);
                       System.out.println("Adding (rf from lRF)"+rf.getRole().getName() +"."+rf.getFunction().getName());
                       this.listRoleFunctions.add(rf);
                       }
                       }
                       }else{
                       //Function to remove
                       System.out.println("remove function");
                       for(RoleFunction roleFunction:this.listRoleFunctions){
                       boolean remove = true;
                       for(Function f:functions){
                       if(roleFunction.getId().equals(f.getId())){
                       remove = false;
                       break;
                       }
                       }
                       if(remove){
                       this.listRoleFunctions.remove(roleFunction);
                       }
                       }
                       }
                       }
                      


                      The only thing which doesn't work is if a user deselect a already saved function assignment.

                      I always get this error:
                      10:49:58,960 INFO [STDOUT] remove function
                      10:49:58,960 SEVERE [component] /roleList.xhtml @72,106 value="#{roleHome.instance.functions}": Error writing 'functions' on type ch.emtm.entity.Role
                      java.util.ConcurrentModificationException
                       at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
                       at java.util.AbstractList$Itr.next(AbstractList.java:343)
                       at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:577)
                      ...


                      Hope someone got input to solve this issue!
                      Thanks in advance for any hint

                      Greets

                      • 8. Re: ManyToMany problem
                        Wolfgang Knauf Master

                        Hi,

                        that's a standard iterator problem, no EJB3 issue ;-):

                        for(RoleFunction roleFunction:this.listRoleFunctions){
                         ...
                         this.listRoleFunctions.remove(roleFunction);

                        You remove an item from the list over which you iterate. Use this "for (int index = this.listRoleFunctions.size() - 1; index >= 0; index--)" to avoid this.

                        Best regards

                        Wolfgang

                        • 9. Re: ManyToMany problem
                          Sven Kilchenmann Newbie

                          Booah thanks for the fast answer :D

                          New to all the things here - i'm so sorry!

                          Next question i got!
                          After i remover the roleFunction from the listRoleFunctions (i've checked, it's okay) and save the removed item is still available in the database!
                          Bad news: there's no stack trace neither in console nor server.log!

                          Hope this issue is as simple to solve as the last one =)

                          Thanks for your assistance!

                          Best regards, Sven

                          • 10. Re: ManyToMany problem
                            Wolfgang Knauf Master

                            Hi Sven (from Germany?),

                            another fast answer, but it will give you a bit to read and think about: http://www.jboss.org/community/wiki/EJB3relationships
                            I hope the section "Managing the (bidirectional) relationship" will provide you with explanations on how to fix this.

                            Wolfgang

                            • 11. Re: ManyToMany problem
                              Wolfgang Knauf Master

                              I see that I posted this link already earlier in this thread. Sorry for this duplicate ;-)!

                              Wolfgang

                              • 12. Re: ManyToMany problem
                                Sven Kilchenmann Newbie

                                Hi Wolfgang

                                close to Germany from [ + ] ;)

                                thanks i will have a look at it again - hope to get it work now.
                                Will return if i get questions or if it's done.

                                • 13. Re: ManyToMany problem
                                  Sven Kilchenmann Newbie

                                  Sorry back again *grml*

                                  I don't get it - cause i'm doing the assignment in the entity not in the bean. Imho there's a difference to the text you've wrote.

                                  I tried to remove the refernces within the remove loop from both sides. No effect =(

                                  • 14. Re: ManyToMany problem
                                    Wolfgang Knauf Master

                                    Hi,

                                    could you post the updated code which removes from the relationship, and also the relationship related snippets of the entities? There were so many changes that I need a full update of it ;-).

                                    I think it is better to keep this code in the session bean, because you are manipulating more than one entity with it.

                                    Best regards

                                    Wolfgang

                                    1 2 Previous Next