5 Replies Latest reply on Feb 29, 2008 8:15 PM by jimk1723

    using OneToMany in view layer

    bcdtech

      For all you SEAM experts, I really could use some direction on correct implementation for my problem.


      I am using JBoss A/S 4.2.2GA, JBoss Seam 2.1.0GA and EJB3 entity beans.


      I have 2 entity beans (EJB3), Employee and Department as follows:


      Employee.java


      @Entity
      @Table(name="EMPLOYEES_TBL")
      @Name("employee")
      public class Employee implements Serializable {
      
          @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
          private int id;
          private String name;
          private long salary;
          
          @ManyToOne
          private Department department;
         
          // getters and setters for id, name and salary omitted 
          
          public Department getDepartment() {
              return department;
          }
          
          public void setDepartment(Department department) {
              this.department = department;
          }
      
      }
      



      Department.java


      @Entity
      @Table(name="DEPARTMENTS_TBL")
      @Name("department")
      public class Employee implements Serializable {
      
          @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
          private int id;
          private String name;
      
          @OneToMany(mappedBy="department")
          private Collection<Employee> employees;
         
          // getters and setters for id and name omitted 
          
          public Department getDepartment() {
              return department;
          }
          
          public Collection<Employee> getEmployees() {
              return employees;
          }
      
      }



       
      I want the view layer (via my XHTML file) to display the department name for the employee, and then allow the user to update the department if required - perhaps through an ajax based lookup.


      My plan is to have the following in my view (viewEmployee.xhtml) to accomplish this?:


      <h:inputText id="departmentName" 
                 value=#{employee.department.name}"
              onChange="someUpdateJavaScriptFunction"/>



      Am I out in left field on this one? Any input or examples would be much appreciated.


      Thanks
      Brent




        • 1. Re: using OneToMany in view layer
          kariem

          Besides the JS part, the approach is ok, if you want to change the name of the employee's department. But I think you really want to change the department the employee is assigned to, right?


          If my assumption is correct, you should rather use a selectOneMenu or something similar. Also have a look at the entity converter (documentation on Seam JSF Controls, look for s:convertEntity).

          • 2. Re: using OneToMany in view layer
            jimk1723

            Quick question on the implications: a user would be able to edit the name of a department that other people may also belong to?


            As for the functionality, Ajax4JSF can handle the asynchronous update. Here's an example of combining Ajax4JSF support with Seam's s:decorate (I ripped this from a seam-gen'ed project, but take a look at the Seam Booking example for more code.)


            <s:decorate id="departmentNameDecoration" template="layout/edit.xhtml">
              <ui:define name="label">departmentName</ui:define>
              <h:inputText id="departmentName" value="#{employee.department.name}">
                <a:support event="onblur" reRender="departmentNameDecoration" />
              </h:inputText>
            </s:decorate>
            



            Binding an input to something like #{employee.department.name} is reasonable, but you're going to need to deal with the case when when employee.department is null. For that case, you will need to add some sort of selectOne element:


            <h:selectOneMenu value="#{employee.department}" required="true">
               <s:selectItems value="#{departments.resultList}" var="departments" label="#{departments.name}" noSelectionLabel="Please Select..."/>
               <s:convertEntity />
            </h:selectOneMenu>
            



            departments is a Query object, an EntityQuery maybe, of all your departments. It may be a weird UI to have both - you may want to restrict functionality on the User page to simply assigning the department. Save editing the department name for a department edit page.


            Oh, and implement equals/hashcode on your entities if you haven't already.

            • 3. Re: using OneToMany in view layer
              bcdtech

              You are correct - I want to change the department for the employee. I am trying to set up my form so they can enter an employee ID number, click a lookup button. That will in turn load the employee record with the department and then the user can change any data, including the department name.


              If I have a simple lookup/edit form with Employee id and name then I can enter the employee id in the ID field and click my lookup button. This submits to my action bean and reloads the page. However, when I add the following:


              <h:inputText id="departmentName" 
                         value=#{employee.department.name}"/>



              I get this error:



              "10:53:35,234 WARN  [lifecycle] /employeeEdit.xhtml @42,101 value="#{employee.department.name}": Target Unreachable, 
              'department' returned null on 'com.brentday.model.Employee'
              javax.el.PropertyNotFoundException: /employee.xhtml @42,101 value="#{employee.department.name}": Target Unreachable, 'market' returned null on 'com.brentday.model.Employee'"



              Any ideas?


              Thanks again.
              Brent



               

              • 4. Re: using OneToMany in view layer
                bcdtech

                You addressed one of my issues. However, what if they want to be taken out of the department (thinking of another case where I may have a relationship that allows the foreign key to be non-existent.


                • 5. Re: using OneToMany in view layer
                  jimk1723

                  Uh, you should be able to get away with:


                  <s:selectItems value="#{departments.resultList}" 
                    var="departments" label="#{departments.name}"
                    noSelectionLabel="Unassigned" hideNoSelectionLabel="false"/>
                  



                  Selecting Unassigned should null the department - afaicr - but I dont' have a working example infront of me. Oh, and remove the required="true" from the h:selectOneMenu.