Model Look up table for a JPA Entity Field - jpa

I'm trying to find out the appropriate relationship to be used in order to model an JPA Entity Field which needs a Look-up table (Comboxbox equivalent on the UI) to select the value from. An example below:
#Entity
public class Employee {
#Id
private int employeeId;
private String name;
private Department department;
}
#Entity
public class Department {
#Id
private int id;
private String name;
}
The instances of Department could be as follows:
Id | Name
-----------------------
100 | Human Resources
101 | Sales
102 | Finances
For an employee, the department field should get a value from one of the above. What should be the JPA annotations for the corresponding fields in both the entities?
Thanks,
Sandeep Joseph

I think you are looking for a unidirectional ManyToOne relationship from Employee to Department, something like this:
#Entity
public class Employee {
#Id
private int employeeId;
private String name;
#ManyToOne
#JoinColumn(name = "department_id", nullable = false)
private Department department;
}
This means an employee must be associated to a single department and a department can be associated to many employees.
If you need to know the list of employees associated to a department then you can make the relationship bidirectional by adding this:
#Entity
public class Department {
#Id
private int id;
private String name;
#OneToMany(mappedBy = "department")
private Collection<Employee> employees;
}

Related

Crieria API query using criteriabuilder.construct with a non existing relationship

Given this very simple DTO:
#Entity
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
#OneToOne
private Employee boss;
}
I'd like to make a query that gathers all employee names and their boss' id, put in a nice clean POJO:
public class EmployeeInfo {
private String name;
private Long bossId;
public EmployeeInfo(String name, Long bossId) {
this.name = name;
this.bossId = bossId;
}
}
This query should be of use:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<EmployeeInfo> query = cb.createQuery(EmployeeInfo.class);
Root<Employee> root = query.from(Employee.class);
query.select(
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
root.get("boss").get("id").as(Long.class)));
result = em.createQuery(query).getResultList();
When a bossId is present in the employee column this works just fine. But when no boss id is set the record will be completly ignored. So how do i treat this non existing boss relation as null or 0 for the construct/multiselect?
In pure SQL it is easy:
SELECT name, COALESCE(boss_id, 0) FROM EMPLOYEE;
But for the love of god i cannot make the criteria api do this.
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
cb.coalesce(root.get("boss").get("id").as(Long.class), 0L)));
The problem is that root.get("boss") generate query with cross join like this from Employee employee, Employee boss where employee.boss.id=boss.id. So records where employee.boss.id is null are ignored.
To solve the problem you should use root.join("boss", JoinType.LEFT) instead of root.get("boss")

JPA Get an entity by intermediate entity

I have 3 entities named Student, Course, and StudentCourse as follows
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue
private Integer id;
private String fullName;
}
#Entity
#Table(name = "course")
public class Course {
#Id
#GeneratedValue
private Integer id;
private String courseName;
}
#Entity
#Table(name = "student_course")
public class StudeCourse {
#Id
#GeneratedValue
private Integer studentId;
private Integer courseId;
private String extraColumn;
}
Restrictions: There are a couple of restrictions
One student can have only one course or no course at all
An extra entity (StudentCourse) is required to hold the relation with primary key as studentId only
StudentCourse is required and hence cannot be skipped
Get Student with Course entity if there is one registered
Help required in some magical code to retrieve Course of Student if there is one assigned.
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue
private Integer id;
private String fullName;
// this is not correct code but just what I want
#JoinEntity(entity=StudentCourse, column="courseId")
private Course course;
}
StudentCourse is required and hence cannot be skipped
Ok, lets work with that.
One student can have only one course or no course at all
Implies that there is a #OneToOne relationship between Student and StudentCourse.
With the given information, the following entity model will work:
#Entity
#Table(name = "student")
public class Student {
#Column(name = "id")
#Id
#GeneratedValue
private Integer id;
#Column(name = "full_name")
private String full_name;
#OneToOne
#PrimaryKeyJoinColumn
private StudentCourse studentCourse;
}
#Entity
#Table(name = "student_course")
public class StudentCourse {
#Column(name = "id")
#Id
#GeneratedValue
private Integer id;
#JoinColumn(name = "id", nullable = false, updatable = false)
#MapsId
#OneToOne
private Student student;
#JoinColumn(name = "course_id")
#ManyToOne
private Course course;
...
}
A quick review:
#OneToOne on the Student.studentCourse field signifies that for every Student, there can be only one StudentCourse, and no more.
#PrimaryKeyJoinColumn on the Student.studentCourse field signifies that the value of the primary key column for Student should be used as the foreign key for the related entity, that is, StudentCourse.
#OneToOne on the StudentCourse.student field signifies that for every StudentCourse, there can be only one Student.
#MapsId on the StudentCourse.student field signifies that the primary key column for StudentCourse should be used as the join column for the association.
To check if a student has a course assigned, simply check if student.getStudentCourse() != null and then get the assigned course as student.getStudentCourse().getCourse().

Effects of Apache Shiro's roles and permissions in existing Data Access Objects classes

I am using spring-boot-dependencies 1.3.5.RELEASE for my application and it runs on Java SE 1.8. I am using Apache Shiro' to mapusergroups inrolestouserpermissionswhereas I am usingDAO(Data Access Object`) for accessing data from database.
Let's say we have an entities such that
Employee "has-a" Department
Department "has-a" Domain
User "has-a" Domain
Entity Classes: Employee
#Entity
#Table(name = "EMPLOYEE")
#Data
#EqualsAndHashCode(of = "id", callSuper = false)
public class Employee {
#Id
#GeneratedValue
private int id;
private String name;
#ManyToOne
#JoinColumn(name="department_id")
private Department dept
}
Entity Classes: Department
#Entity
#Table(name="DEPARTMENT")
#Data
#EqualsAndHashCode(of = "id", callSuper = false)
public class Department {
#Id
#GeneratedValue
private int id;
private String name;
#ManyToOne
#JoinColumn(name="domain_id")
private Domain domain
#OneToMany(mappedBy="department")
private Set<Employee> employees;
}
Entity Classes: Domain
#Entity
#Table(name="DOMAIN")
#Data
#EqualsAndHashCode(of = "id", callSuper = false)
public class Domain{
#Id
#GeneratedValue
private int id;
private String name;
}
Now I would like to restrict User (a login user) to see only those Employees which are associated with the Departments whose Domain has an access to the User. Is there any way to achieve this without changing queries in DAO classes OR to do this with minimum code changes? Thank You.
Which Realm are you using? If you are using the JdbcRealm you should be able to set userRolesQuery to a query of your choice.

Jpa OneToMany with condition

I have 2 tables:
The first is "Persons":
person_id,
person_name
The second is "PersonsGraphs":
person_id1,
person_id2,
relation_type
I'm looking for a way to build a "family tree".
My first option is: load personGraphs into a HashTable and then recursively build the tree.
The second option I have come up with: use #OneToMany jpa-relation. This can work, but sometimes I have some relation_types that I want/don't want to include. Are there any options that would allow me to set some condition on the #OneToMany relation while using #JoinTable?
Thanks!
Oak
Try to use Hibernate #Where annotation, for example:
#Entity
public class Person {
#Id
#GeneratedValue
private Integer id;
private String name;
#Enumerated(EnumType.STRING)
private Gender gender;
#ManyToOne
private Person parent;
#Where(clause = "gender = 'MALE'")
#OneToMany(mappedBy = "person")
private List<Person> sons;
#Where(clause = "gender = 'FEMALE'")
#OneToMany(mappedBy = "person")
private List<Person> daughters;
}
public enum Gender {
MALE, FEMALE
}
I would recommend creating a Relationship class to model the join table.
Person - OneToMany - relations - Relationship - ManyToOne source - ManyToOne target
In EclipseLink you can add an Expression criteria to any relationship mapping,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/MappingSelectionCriteria

efficient JPQL: update entities in #onetomany

i have two entities Customer and Order (trivial setters and getters excluded)
#Entity
public class Customer {
#GeneratedValue
#Id
private int id;
#OneToMany
List<Order> orderList;
}
#Entity
public class Order {
#GeneratedValue
#Id
private int id;
#ManyToOne
Customer customer;
private boolean paid;
public Order(Customer customer) {
this.customer = customer;
customer.getOrderList().add(this)
}
}
Now i want to set 'paid = true' for all the orders of a given customer
Below query seem to do the trick, but I get a feeling it is innefficient and the fact that i stored the reverse relationship in Customer.orderList hints that there should be some other way to do this.
UPDATE Order o SET o.paid = true WHERE EXISTS
(SELECT c.orderList FROM Customer c WHERE o MEMBER OF c.orderList AND c = :customer)
I'm using container managed transactions, glassfish and javaDb. But I'd prefer if improvements could be done in JPA/JPQL domain and not specific to container or db.
private id; ?? missed field type
Add to #OneToMany annotation,cascade = CascadeType.All
Customer entity = entityManager.find(Customer.class, id)
for (Order order : entity.getOrderList())
{
order.setPaid(true);
}
if you are using cantainer managed transaction then true will be saved to DB