I'm trying to add to my crud services the possibility to specify what nested relationship I need so I don't have to read everything from the database.
Take for example I have those entities
Company.java
private List<Department> departments;
private SalaryCode salaryCode;
Department.java
private List<Employee> employees;
private Company company;
private SalaryCode salaryCode;
Employee.java
private Department department;
private SalaryCode salaryCode
And my Criteria query for now is this :
Session session = sessionFactory.openSession();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = builder.createQuery(clazz);
Root<T> root = criteriaQuery.from(clazz);
//nestedRelationships is a varargs passed as parameters
for(String nestedRelationship : nestedRelationships) {
root.fetch(nestedRelationship, JoinType.LEFT);
}
List<T> result = session.createQuery(criteriaQuery.select(root)).list();
The thing is if I specify "department" as nestedRelationship and querying for Employee entity it works well but when I try to specify "department.salaryCode" it doesn't work saying " Unable to locate Attribute with the the given name ". Of course I'm fetching "department" first and then "department.salaryCode".
Is it supported? If yes how does it work and if it's not supported what can I do?
I found a solution by making an algorithm using the Root element
protected void fetch(Root<T> root, String... joins) {
//Sort the joins so they are like this :
//A
//A.F
//B.E
//B.E.D
//B.G
Arrays.sort(joins);
Map<String, Fetch> flattenFetches = new HashMap<>();
for (String join : joins) {
try {
if (join.contains(".")) {
String[] subrelations = join.split("\\.");
Fetch lastRelation = null;
int i;
for (i = subrelations.length - 1; i >= 0; i--) {
String subJoin = String.join(".", Arrays.copyOf(subrelations, i));
if (flattenFetches.containsKey(subJoin)) {
lastRelation = flattenFetches.get(subJoin);
break;
}
}
if (lastRelation == null) {
lastRelation = root.fetch(subrelations[0], JoinType.LEFT);
flattenFetches.put(subrelations[0], lastRelation);
i = 1;
}
for (; i < subrelations.length; i++) {
String relation = subrelations[i];
String path = String.join(".", Arrays.copyOf(subrelations, i + 1));
if (i == subrelations.length - 1) {
Fetch fetch = lastRelation.fetch(relation, JoinType.LEFT);
flattenFetches.put(path, fetch);
} else {
lastRelation = lastRelation.fetch(relation, JoinType.LEFT);
flattenFetches.put(path, lastRelation);
}
}
} else {
Fetch fetch = root.fetch(join, JoinType.LEFT);
flattenFetches.put(join, fetch);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
and to use it I just have to do for example :
employeeController.getAll("punches", "currentSchedule.shifts", "defaultDepartment.currentSchedule.shifts",
"defaultDepartment.company.currentSchedule.shifts", "bankExtras")
I would like to comment the algorithm but I do not have time and it's pretty easy to understand