I have 3 entities : EntityEntity, EntityTaskEntity and EntityTaskStatusEntity.
EntityEntity has the following properties:
@Entity
@Table(name = "entities")
@Getter @Setter
@AllArgsConstructor @NoArgsConstructor
@EqualsAndHashCode
public class EntityEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 30)
private String entityId;
@Column(length = 100, unique = true)
private String name;
@OneToMany(mappedBy = "entity", cascade={CascadeType.ALL}, fetch = FetchType.EAGER)
private List<EntityTaskEntity> entityTasks;
}
EntiTaskEntity has the following implementation:
@Entity
@Table(name = "entity_tasks")
public class EntityTaskEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 30, unique = true)
private String entityTaskId;
@Column(length = 100)
private String workflowTaskName;
@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
@JoinColumn(name = "entity_task_status_id")
private EntityTaskStatusEntity status;
@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY)
private EntityEntity parentEntity;
@JsonManagedReference
@OneToMany(mappedBy = "parentEntity")
private List<EntityEntity> childEntities;
}
Finally, the EntityTaskStatusEntity:
@Entity
@Table(name = "entity_task_statuses")
@Getter @Setter
@AllArgsConstructor @NoArgsConstructor
@EqualsAndHashCode
public class EntityTaskStatusEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 30, unique = true)
private String entityTaskStatusId;
@Column(length = 100, unique = true)
private String name;
}
I do use jpa repositories and do queries on EntityEntity using entityId which is unique.
I do queries on EntityTaskStatusEntity using entityTaskStatusId which is also unique.
I have the following method in java for creating a Specification:
private Specification<EntityEntity> entitySpecificationQueryConfigurer (
List<String> entityTaskStatusIdParams, ...) {
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if(entityTaskStatusIdParams != null) {
predicates.add(setInPredicate(
entityTaskStatusIdParams, root, query, criteriaBuilder));
root.fetch("childEntities", JoinType.LEFT);
}
// I have other predicates....
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
My call to this entitySpecificationQueryConfigurer
Specification<EntityEntity> specification = entitySpecificationQueryConfigurer(entityTaskStatusIdParams);
List<EntityEntity> entityEntities = repository.findAll(specification);
Here is my implementation of setInPredicate:
private Predicate setAllInPredicate(
String paramString,
Root<EntityEntity> root,
CriteriaQuery<?> query,
CriteriaBuilder criteriaBuilder) {
Set<String> entityTaskStatusIdParams = Stream.of(paramString.split(","))
.collect(Collectors.toSet());
// Subquery to count all tasks of an entity
Subquery<Long> totalTasksSubquery = query.subquery(Long.class);
Root<EntityTaskEntity> taskRoot = totalTasksSubquery.from(EntityTaskEntity.class);
totalTasksSubquery.select(criteriaBuilder.count(taskRoot.get("id")));
totalTasksSubquery.where(criteriaBuilder.equal(taskRoot.get("entity"), root));
// Subquery to count tasks of an entity with statuses in the given list
Subquery<Long> matchedTasksSubquery = query.subquery(Long.class);
Root<EntityTaskEntity> matchedTaskRoot = matchedTasksSubquery.from(EntityTaskEntity.class);
matchedTasksSubquery.select(criteriaBuilder.count(matchedTaskRoot.get("id")));
Join<EntityTaskEntity, EntityTaskStatusEntity> statusJoin = matchedTaskRoot.join("status");
matchedTasksSubquery.where(criteriaBuilder.and(
criteriaBuilder.equal(matchedTaskRoot.get("entity"), root),
statusJoin.get("entityTaskStatusId").in(entityTaskStatusIdParams)
));
// Ensure the total number of tasks is equal to the number of matched tasks
return criteriaBuilder.equal(totalTasksSubquery, matchedTasksSubquery);
}
In my entitySpecificationQueryConfigurer method I do have several predicates I use for my Specification.
My issue is that i don’t retrieve childEntities in my results. If i don’t have any entityTaskStatusIdParams then my results return childEntities…