3

I have a ManyToMany relationship established with a join table that is exactly like the one described on the Java Persistence wiki Example of a ManyToMany relationship annotations. Using that wiki example of Employees & Projects as a reference, the code listed in the example works fine to create three tables: EMP, PROJ and the EMP_PROJ join table. What I would like to do is use that EMP_PROJ join table in a separate entity. I don't want to add additional columns to the EMP_PROJ join table. For example, suppose an administrator associates projects with an employee. That list is stored in EMP_PROJ. What I would like to do is create a separate entity called ManagerReport that will return, for an employee, the list of projects associated with that employee. The manager can then enter specific info regarding each project for the employee, like start date, end date, performance, etc.

Below are the tables and sample code pulled from the wiki page.

EMPLOYEE (table)
ID  FIRSTNAME   LASTNAME
1   Bob     Way
2   Sarah   Smith

EMP_PROJ (table)
EMP_ID  PROJ_ID
1   1
1   2
2   1

PROJECT (table)
ID  NAME
1   GIS
2   SIG

@Entity
public class Employee {
  @Id
  @Column(name="ID")
  private long id;
  ...
  @ManyToMany
  @JoinTable(
      name="EMP_PROJ",
      joinColumns={@JoinColumn(name="EMP_ID", referencedColumnName="ID")},
      inverseJoinColumns={@JoinColumn(name="PROJ_ID", referencedColumnName="ID")})
  private List<Project> projects;
  ...
}
Sean
  • 65
  • 1
  • 6

1 Answers1

4

You will have to create a ManagerReportProject entity which maps to EMP_PROJ table with @Table annotation.

In Employee entity, instead of @ManyToMany mapping for a collection of Projects use @OneToMany mapping for collection mapping to ManagerReportProject entities.

You will still be able to get a list of employee's projects because each ManagerReportProject further points to Project. You can even create a helper getProjects() method inside Employee to get a list of projects. Method must be annotated with @Transient to mark getProjects() method as not JPA persitent (by default all properties or fields inside Entity mappings are persitent)

     @Entity
     public class Employee 
     {
          @Id
          @Column(name="ID")
          private long id;
          ...
          @OneToMany...
          private List<ManagerReportProject> managerReportProjects;
          ...

          /*
          YOU DON'T NEED THIS ANYMORE:
          @ManyToMany
          @JoinTable(
              name="EMP_PROJ",
              joinColumns={@JoinColumn(name="EMP_ID", referencedColumnName="ID")},
              inverseJoinColumns={@JoinColumn(name="PROJ_ID", referencedColumnName="ID")})
          private List<Project> projects;

           */

       @Transient
       public List<Project> getProjects()
       {
          List<Project> projects = new ArrayList<Project>();
          for(ManagerReportProject managerReportProject: managerReportProjects)
          {
             projects.add(managerReportProject.getProject());
          }
          return projects;
       }
     ...
    }

   

ManagerReportProject should point to Employee, Project and Manager entity with @ManyToOne association.
Put manager report specific columns into ManagerReportProject (start date, end date, performance, etc.).
ManagerReportProject maps to EMP_PROJ table with @Table annotation.

@Entity
@Table(name= "EMP_PROJ")
public class ManagerReportProject{
  @Id
  @Column(name="ID")
  private long id;

//manager report columns
  private Date startDate;
  private Date endDate;
  performance, etc. 

  @ManyToOne...
  private Manager manager;

  ...
  @ManyToOne...
  private Employee employee;

  @ManyToOne...
  private Project project;

  ...
}

   

Create a Manager entity, use @OneToMany for collection mapping to ManagerReportProject entities:

@Entity
public class Manager {
  @Id
  @Column(name="ID")
  private long id;
  ...
  @OneToMany...
  private List<ManagerReportProject> managerReportProjects;
  ...
}

   

Now you can enter specific info regarding each project for the employee, like start date, end date, performance, etc. This is a sketch just to demonstrate an idea of how to edit existing manager report for a specific empolyee working for a specific manager:

Emyployee employee = ...
Manager manager = ...
List<ManagerReportProject> managerReportProjects= employee.getManagerReportProjects()
for(ManagerReportProject managerReportProject: managerReportProjects )
{
    if(manager.equals(managerReportProject.getManager()))
    {
       Project project = managerReportProject.getProject();

       managerReportProject.setStartDate(...);
       managerReportProject.setEndDate(...);
       managerReportProject.setperformance(...);
       ...

    }

}
Sergej Panic
  • 854
  • 5
  • 8
  • Thanks very much! This works well. I appreciate the detailed reply. – Sean Sep 18 '13 at 00:21
  • The limitation of this solution is that ManagerReportProject does not restrict the list of projects for an employee based on the EMP_PROJ join table. In other words, if I create 3 project entries and assign 2 of those to one employee, in the ManagerReportProject, I should be restricted to editing only those 2 projects. I can add an entry for the 3rd project, which is not assigned to the employee. It appears that this is because the EMP_PROJ table is not referenced in ManagerReportProject, so there is not restriction to only projects assigned to an employee. – Sean Sep 18 '13 at 21:56
  • I have edited my post to be more clear. ManagerReportProject needs to map to the EMP_PROJ table with `@Table(name="EMP_PROJ")` annotation. In Employee entity, instead of @ManyToMany mapping for a collection of Projects use `@OneToMany` mapping for collection mapping to ManagerReportProject entities. You will still be able to get a list of employee's projects because each ManagerReportProject further points to Project. – Sergej Panic Sep 19 '13 at 09:34
  • Thank you, Sergej. What seems to have been lost with your edit is the association of projects to an employee that are persisted (originally in EMP_PROJ). This is important to persist because the ManagerReportProject should be limited to displaying only the projects associated with a selected employee. While the `@Transient` property provides a list of projects in the Employee view, the mapping of projects to employee which can then be accessed by a manager is gone. This mapping was originally persisted in the EMP_PROJ join table. – Sean Sep 19 '13 at 19:26
  • Yes the `@ManyToMany` mapping is gone and replaced with ManagerReportProject entity which maps to EMP_PROJ table. ManagerReportProject serves two functions: first is to model the join table (i.e. it "simulates" `@ManyToMany` mapping) and second is to hold additional columns. Here is the same example explained in more details: http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns – Sergej Panic Sep 19 '13 at 20:30