Use Join Table in Separate Entity - java

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;
...
}

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(...);
...
}
}

Related

Filter one-to-many children while requesting parent Entity with HSQL

Hello there is my model
#Entity
public class Group {
#Id
#GeneratedValue
private Long id;
#OneToMany(
cascade = CascadeType.ALL
)
private List<User> users;
//Constructors, getters and setters removed for brevity
}
#Entity
public class User{
#Id
#GeneratedValue
private Long id;
private boolean valid;
//Constructors, getters and setters removed for brevity
}
Is it possible to make a HSQL request to select a Group by id, but keeping in the User list, only the users with 'true' in the "valid" field ?
If you want to use HSQL to return JPA entity tree (simple way), the answer is no.
Though, you can write this:
select g from Group g
left join g.users u with u.valid = true
where g.id = 123
your users collection won't be initialized. If you add fetch keyword to the join, you get an error:
QuerySyntaxException: with-clause not allowed on fetched associations; use filters
Which leads you to other solution, using annotation #Filter. But you need to enable the filter, and then you have problem with updating the entity read with the filter turned on (collection synchronization).

Many to Many relation with dependency inversion

I have a multimodule application with two modules:
department-management
communication-management
now in my department-management i have an entity Department and in communication-management module i have MailingGroup entity.
Also the communication-management depends on department-management module.
Now i want to have bidirectional ManyToOne relation between Department and MailingGroup
#Entity
public class Department {
#OneToMany(mappedBy = "department")
List<MailingGroup> mailingGroups;
}
#Entity
public class MailingGroup{
#ManyToOne
#JoinColumn(name = "DEPARTMENT_ID")
Department department;
}
This, of course, is not archiveable the way above, but can i archive this bidirectional relation using interfaces? My initial idea was to solve it like this:
public interface MailingGroupProvider {
Department getDepartment()
}
#Entity
public class Department {
#OneToMany(mappedBy = "department")
List<MailingGroupProvider> mailingGroups;
}
#Entity
public class MailingGroup implements MailingGroupProvider {
#ManyToOne
#JoinColumn(name = "DEPARTMENT_ID")
Department department;
}
But it raises questions:
Is this prefered solution in such cases?
What methods should my interface provide to be treated as Entity by JPA?
is this even possible what im trying to do?
First Approach is Perfect: You need to add a Relationship in Both Entity Sides.
departmentid is the foreign key of the mailing group Table. Apply Relationship in both entity sides it will work.
#OneToMany Relationship means u can have one Department can have Many Communication.
Bidirectional means suppose if u do any operation in Communication Management like deleting Communication it will affect on Department Table Also. It will Remove Departmentid matched in the Department Table

JPA OneToMany with Jointable, deleting a link deletes right-side object

(OpenJPA2.x) I have Parent->(linktable)->Category relation. If I remove category from parent's category array it gets properly deleted from the linktable (unlinked). Adding a new category to an array gets inserted to the linktable. However problem is category target entity is also deleted from Category table. I have debugged jdbc queries and it's performed by OpenJPA library, db tables don't have a cascaded delete constraint.
Parent(key=ServerId,Code)
ServerId|Code |Name
1 |code1|name1
1 |code2|name2
1 |code3|name3
2 |code1|name4
Category(key=ServerId,Code)
1 |cat1 |child1
1 |cat2 |child2
2 |cat2 |child3
LinkTable(key=ServerId,PCode,CCode)
ServerId|PCode|CCode
1 |code1|cat1
1 |code1|cat2
1 |code3|cat1
Parent->Categories are linked using OneToMany annotation. Category does not know where it was linked from so prefer keeping that entity class clean as possible without any link annotations.
#Entity #Table(name="Parent") #Access(AccessType.FIELD)
public class Parent {
#EmbeddedId Parent.PK pk; // contains serverId+code fields
private String name;
#OneToMany(fetch=FetchType.LAZY, orphanRemoval=true, cascade=CascadeType.PERSIST)
#JoinTable(name="LinkTable",
joinColumns={
#JoinColumn(name="ServerId", referencedColumnName="ServerId", nullable=false),
#JoinColumn(name="PCode", referencedColumnName="Code", nullable=false)
},
inverseJoinColumns={
#JoinColumn(name="ServerId", referencedColumnName="ServerId", nullable=false),
#JoinColumn(name="CCode", referencedColumnName="Code", nullable=false)
}
)
private List<Category> cats;
public List<Category> getCategories() { return cats; }
}
#Entity #Table(name="Category") #Access(AccessType.FIELD)
public class Category {
#EmbeddedId Category.PK pk; // serverId,Code fields
private String name;
// this entity don't have OneToMany,ManyToOne,etc.. links back to parent
}
This is a legacy application I must use a composited primary keys, but it should not be a JPA problem I guess, after all this is a valid sql schema pattern.
You annotated the association with orphanRemoval=true. That precisely means that categories which are removed from their parent, and are thus orphan, must be removed.

JPA with hibernate provider many-to-many fetch mode

I have 2 JPA entities User and Course:
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
#ManyToMany
#JoinTable(name="UserCourse")
private Set<Course> courses;
// getters and setters
}
#Entity
#Cacheable
public class Course {
#Id
#GeneratedValue
private Integer id;
// getters and setters
}
Course is cacheable. hibernate.max_fetch_depth is set to 0.
What I need is when I iterate through a user's courses, hibernate should fire a simple SELECT query to fetch courses from join-table UserCourse and load Course entity from L2 cache.
But instead, hibernate always seem to be firing a join-query between UserCourse and Course.
So the question is -
In case of ManyToMany association, is there a way to force hibernate to fire a simple non-join SELECT on join-table and fetch the related cacheable entity from L2 cache?

Deleting Objects in Many to Many association with Hibernate and Java

I've been searching for days but can't seem to find the answer.
Given this many to many (employee/meeting)
#Entity
#Table(name="EMPLOYEE")
public class Employee {
#Id
#Column(name="EMPLOYEE_ID")
#GeneratedValue
private Long employeeId;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name="EMPLOYEE_MEETING",
joinColumns={#JoinColumn(name="EMPLOYEE_ID")},
inverseJoinColumns={#JoinColumn(name="MEETING_ID")})
private Set<Meeting> meetings = new HashSet<Meeting>();
}
#Entity
#Table(name="MEETING")
public class Meeting {
#Id
#Column(name="MEETING_ID")
#GeneratedValue
private Long meetingId;
#ManyToMany(mappedBy="meetings")
private Set<Employee> employees = new HashSet<Employee>();
}
I can add employees to a meeting and it shows up in the employee_meeting table.
When I do get a meeting object and delete it, it's also gone from the join table but remains in the employee set... Is this the expected behaviour?
Here's how I would remove a meeting object
session.delete(meeting);
transaction.commit();
At this point it's gone from the table.
Thanks!
Yes this is correct behaviour. If you have many-to-many relationship, then you need to delete it manually. Please refer this link for hibernate collection mapping strategy

Categories