Is it possible to query the join table using HQL? - spring

My Database:
WorkflowProcess
id | name
WorkflowProcessToWorkflowProcess
ancestor | descendent
I need to query for root WorkflowProcess. With this table structure, I'm looking to query something like SELECT * FROM WorkflowProcess WHERE id NOT IN (SELECT DISTINCT descendent FROM WorkflowProcessToWorkflowProcess)
My WorkflowProcess entity:
private Collection<WorkflowProcessEntity> workflowProcesses;
#JoinTable(name = "Workflow_Process_to_Workflow_Process", joinColumns = {
#JoinColumn(name = "ancestor", referencedColumnName = "id")}, inverseJoinColumns = {
#JoinColumn(name = "descendent", referencedColumnName = "id")})
#ManyToMany()
public Collection<WorkflowProcessEntity> getWorkflowProcesses() {
return workflowProcesses;
}
public void setWorkflowProcesses(Collection<WorkflowProcessEntity> workflowProcesses) {
this.workflowProcesses = workflowProcesses;
}
Is it possible to accomplish this with HQL?

Try something like this:
select child
from WorkflowProcess parent right join parent.workflowProcesses child
where parent is null

Related

Spring boot lazy collection not loaded properly

I have 3 entities:
User, Shelter and ShelterUsers
ShelterUsers is a join table for many to many relationship between Shelter and User with additional column. (design based on this suggestion)
I also have a #OneToMany relationship from User to Role which also uses a join table but without an additional field so there is no entity for that table
When I get the User from the database Roles are also attached with a join if I set the fetch to EAGER and they're loaded with additional query if I set fetch to LAZY (even without calling the user.getRoles() explicitly, which I also don't understand).
Problem is that ShelterUsers are not attached to user, no matter if I set it to EAGER or LAZY. After inspecting the sql that hibernate generates it seems like it generates the wrong sql:
First query:
SELECT user0_.id AS id1_7_0_,
user0_.created_at AS created_2_7_0_,
user0_.email AS email3_7_0_,
user0_.first_name AS first_na4_7_0_,
user0_.last_name AS last_nam5_7_0_,
user0_.password AS password6_7_0_,
user0_.updated_at AS updated_7_7_0_,
user0_.username AS username8_7_0_,
roles1_.user_id AS user_id1_8_1_,
role2_.id AS role_id2_8_1_,
role2_.id AS id1_4_2_,
role2_.name AS name2_4_2_
FROM users user0_
LEFT OUTER JOIN users_roles roles1_ ON user0_.id=roles1_.user_id
LEFT OUTER JOIN ROLES role2_ ON roles1_.role_id=role2_.id
WHERE user0_.id=?
Second query:
SELECT shelters0_.shelter_id AS shelter_3_6_0_,
shelters0_.id AS id1_6_0_,
shelters0_.id AS id1_6_1_,
shelters0_.shelter_id AS shelter_3_6_1_,
shelters0_.user_id AS user_id4_6_1_,
shelters0_.user_role AS user_rol2_6_1_,
user1_.id AS id1_7_2_,
user1_.created_at AS created_2_7_2_,
user1_.email AS email3_7_2_,
user1_.first_name AS first_na4_7_2_,
user1_.last_name AS last_nam5_7_2_,
user1_.password AS password6_7_2_,
user1_.updated_at AS updated_7_7_2_,
user1_.username AS username8_7_2_
FROM shelter_users shelters0_
LEFT OUTER JOIN users user1_ ON shelters0_.user_id=user1_.id
WHERE shelters0_.shelter_id=?
Where clause should be WHERE user1_.id = ?
Here is all relevant code:
User:
#Entity
#Data
#Table(name = "users")
public class User {
...
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_roles",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id")
)
private Collection<Role> roles = new ArrayList<>();
#OneToMany(mappedBy = "shelter")
private Collection<ShelterUsers> shelters = new ArrayList<>();
...
}
Shelter:
#Entity
...
#Table(name = "shelters")
public class Shelter {
...
#OneToMany(mappedBy = "user")
private List<ShelterUsers> users = new ArrayList<>();
}
ShelterUsers:
#Entity
public class ShelterUsers {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
#ManyToOne
#JoinColumn(name = "shelter_id", referencedColumnName = "id")
private Shelter shelter;
#Enumerated(EnumType.STRING)
#Column(name = "user_role")
private ShelterUserRole userRole;
}
Recap:
Roles get loaded with user no matter the fetch type.
ShelterUsers are not loaded
JSON example:
{
...
"roles": [
{
"id": 1,
"name": "ROLE_ADMIN"
}
],
"shelters": [],
...
}
What I would ideally want to achieve is this:
{
"roles": [
{
"id": 1,
"name": "ROLE_ADMIN"
}
],
"shelters": [
{
//Shelter entity (not ShelterUser)
},
]
}

how can i make query with jpa many to many and list of condition must be all true

I have 2 entities User and Prestation with many to many relationship. I want to get all users having specific Prestation like a list of ID Prestation
my query :
#Query("SELECT distinct u FROM User u JOIN u.prestation p where p.id In (:prestationsList)")
public List<User> findAllUser(#Param("prestationsList") List<Integer> prestationsList);
But this did not give me the correct data, because (In) return user if one element of my prestationList is true
my User :
#Entity
public class User {
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "users_prestations",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "prestation_id")})
private Set<Prestations> prestation = new HashSet<>();
}
my Prestations :
#Entity
public class Prestations {
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "prestation")
private Set<User> user = new HashSet<>();
}
How should I write this query in JPA?
try using this JPQL query
#Query("SELECT * FROM User u left join u.prestation p where p.id In (:prestationsList)")
public List<User> findAllUser(#Param("prestationsList") List<Integer> prestationsList);
if this doesn't work try a native query

Inner join in spring boot data jpa

I am using spring boot data jpa 1.4 and I'm fairly new to it.
My table definition is here. Its fairly simple, there are 2 tables (Groups and Users).
The group table contains group_id(primary key), group_name, group_active(values=Y/N).
The group table can ideally have only one row which is has group_active to 'Y', the rest should have 'N'
The user table contains user_id(primary key), user_name, group_id(foreign key from group).
Following are my entity classes
Group:
#Entity
#Table(schema = "HR", name = "GROUPS")
public class Group {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "GROUP_ID")
private Long id;
#Column(name = "GROUP_NAME")
private String name;
#Column(name = "GROUP_ACTIVE")
private String active;
User:
#Entity
#Table(schema = "HR", name = "USERS")
public class User {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "USER_ID")
private Long id;
#Column(name = "USER_NAME")
private String name;
#Column(name = "GROUP_ID")
private Long groupId;
#ManyToMany
#JoinTable(
schema = "HR",
name = "GROUPS",
joinColumns = {#JoinColumn(table = "GROUPS", name = "GROUP_ID", insertable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(table = "USERS", name = "GROUP_ID", insertable = false, updatable = false)}
)
#WhereJoinTable(clause = "GROUP_ACTIVE='Y'")
private List<Group> group;
Repository class:
public interface UserRepository extends CrudRepository<User, Long>{
List<User> findByName (String name);
}
Query: This is the query I want to execute, which is a simple inner join.
SELECT U.*
FROM HR.USER U, HR.GROUP G
WHERE U.GROUP_ID=G.GROUP_ID
AND G.GROUP_ACTIVE='Y'
AND U.USER_NAME=?
What would be the correct way to write the #JoinTable or #JoinColumn such that I always get back one user that belongs to the active group with the name ?
I have done some tests based on your set-up and the solution would need to use filters (assuming there is only one Group with Group_Activity = 'Y'):
Group Entity
#Entity
#Table(schema = "HR", name = "GROUPS")
public class Group {
#OneToMany(mappedBy = "group")
#Filter(name = "activityFilter")
private Set<User> users;
User Entity
#Entity
#Table(schema = "HR", name = "USERS")
#FilterDef(name="activityFilter"
, defaultCondition="group_id =
(select g.id from groups g where g.GROUP_ACTIVE='Y')")
public class User {
#ManyToOne
#JoinColumn(name = "group_id")
private Group group;
When making a query
session.enableFilter("activityFilter");
session.createQuery("select u from Group g inner join g.users u where u.user_name = :userName");
Additionally if there are many groups with activity = 'Y' then try this:
#FilterDef(name="activityFilter"
, defaultCondition="group_id in
(select g.id from group g where g.GROUP_ACTIVE='Y')")

Spring Crud on Nested Property

I have a spring crud repository:
#Repository
public interface CrudCVVacancyMatchRepository extends CrudRepository<CVVacancyMatchEntity, Long> {
The CVVacancyMatchEntity object has an Vacancy property. I'm trying to write a query method on properties of the Vacancy property.
The following query method works fine (Vacancy has a string property called name):
Iterable<CVVacancyMatchEntity> findByVacancyName(String name);
But Vacancy also has properties as a set:
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "vacancy_industries", joinColumns = { #JoinColumn(name = "fk_vacancy", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "fk_industry", referencedColumnName = "id") })
private final Set<IndustryEntity> industries = Sets.newHashSet();
This doesn't work:
Iterable<CVVacancyMatchEntity> findByVacancyIndustries(Set<IndustryEntity> industryEntities);
I get ERROR SqlExceptionHelper:146 - Syntax error in SQL statement
select cvvacancym0_.id as id1_19_, cvvacancym0_.comment as comment2_19_, cvvacancym0_.cv_id as cv_id4_19_, cvvacancym0_.rating as rating3_19_, cvvacancym0_.user_id as user_id5_19_, cvvacancym0_.vacancy_id as vacancy_6_19_ from cv_vacancy_match cvvacancym0_ cross join vacancy vacancyent1_ cross join vacancy_industries industries2_, industry industryen3_ where cvvacancym0_.vacancy_id=vacancyent1_.id and vacancyent1_.id=industries2_.fk_vacancy and industries2_.fk_industry=industryen3_.id and .=? [42001-182]
Any idea?

JPA Self Join using JoinTable

I have 1 entity call Item in which I want to be able to link parent items to children. to use a join table to create a parent/child relationship. I haven't been able to get any good documentation on. So if anyone has any thoughts I'm all ears.
Here is what I have... which works most of the time.
public class Item implements java.io.Serializable {
#Id
private Long id;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinTable(name = "ITEMTOITEM", joinColumns = { #JoinColumn(name = "ITEMID") }, inverseJoinColumns = { #JoinColumn(name = "PARENTITEMID") } )
private Item parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Item> children;
}
At times when I want to bring back objects that are tied to this item table I am getting an error of the following:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.webflow.engine.ActionExecutionException: Exception thrown executing [AnnotatedAction#6669ff5 targetAction = com.assisted.movein.web.common.nav.NavAction#6edf74b7, attributes = map['method' -> 'handleEntry']] in state 'oneTimeChargesAndFeesView' of flow 'in-flow' -- action execution attributes were 'map['method' -> 'handleEntry']'; nested exception is Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b04-fcs (04/11/2008))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-00904: "PARENTITEM_ITEMID": invalid identifier
Error Code: 904
Call: SELECT ITEMID, ITEMSHORTDESC, EFFENDDATE, ITEMDESC, PARENTITEM_ITEMID, ITEMTYPECODE FROM ITEM WHERE (ITEMID = ?)
bind => [1250]
Query: ReadObjectQuery(com.domain.Item)
Any help would be appreciated.
Try to use #JoinColumninstead:
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "PARENTITEMID", referencedColumnName = "ITEMID")
private Item parent;
#OneToMany(
cascade = {CascadeType.ALL},
orphanRemoval = true,
fetch = FetchType.LAZY
)
#JoinColumn(name = "PARENTITEMID")
private List<Item> children;
After a lot of reading on JPA 2.0 I figured out that I needed a newer version of Eclipselink 2.3+ in order to support what I was trying to do. Here is the code that actually worked in my case, but it will not work due to our dependency on an older version [EclipseLink 2.0.2]. Also another project's is still using Toplink-essentials JPA 1.0 which again does like this notation.
public class Item {
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinTable(name = "ITEMINCENTIVESMAPPING",
joinColumns = { #JoinColumn(name = "INCENTIVEITEMID", referencedColumnName = "ITEMID", insertable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "ITEMID", referencedColumnName = "ITEMID", insertable = false, updatable = false) } )
private Item parentItem;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "ITEMINCENTIVESMAPPING",
joinColumns = { #JoinColumn(name = "INCENTIVEITEMID", referencedColumnName = "ITEMID") },
inverseJoinColumns = { #JoinColumn(name = "ITEMID", referencedColumnName = "ITEMID") } )
private List<Item> items;
}
I believe #JoinTable is only allowed on a #OneToOne or #OneToMany or #ManyToMany, I don't think it makes any sense on a #ManyToOne. Use a #JoinColumn, or a #OneToOne.
Also your #OneToMany does not make sense, the mappedBy must be an attribute and you have no parentItem, it should be parent, and parent should use a #JoinColumn.

Resources