ManyToMany select query in JPA2(JPQL) - many-to-many

I have two tables: User and Role in ManyToMany relationship.
#Entity
#Table(name = "user")
public class User implements Serializable {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
#ManyToMany
#JoinTable(name = "user_role",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
//getters, setters
}
and
#Entity
#Table(name = "role")
public class Role implements Serializable {
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long roleId;
#Column(name = "role_code")
private String roleCode;
#ManyToMany(mappedBy = "roles")
#JsonIgnore
private Set<User> users;
//getters,setters
}
I want select all users and ALL HIS roles if user have role for example 'ROLE_USER'.
I did it in native sql but i would like to use JPQL or CriteriaQuery.
I tried in JPQL(changing earlier fetching type to EAGER becouse in subquery I can't use join fetch):
public List<User> findUsersByRole(String roleName, int startNumber, int endNumber) {
Query q = em.createQuery("select u from User u join fetch u.roles r WHERE u.userId in (SELECT uu.userId FROM User uu join uu.roles rr WHERE rr.roleCode like :roleName)")
.setParameter("roleName", roleName)
.setFirstResult(startNumber)
.setMaxResults(endNumber);
return q.getResultList();
}
and it works as I want but is it possible without changing Fetching type to EAGER?
Thank you for response.

You can do:
public List<User> findUsersByRole(String roleName, int startNumber, int endNumber) {
Query q = em.createQuery("select u from User u join fetch u.roles join u.roles r WHERE r.roleCode like :roleName")
.setParameter("roleName", roleName)
.setFirstResult(startNumber)
.setMaxResults(endNumber);
return q.getResultList();
}

Related

How can I use post method data in back end to save many to many relationship data with #JsonIgnore annotation.My joining table is not updating

How can I use the data send through post method, and save those data in a many to many relationship? I used #JsonIgnore annotation to stop the recursion.
I have implemented two entities.One is Employee and the other is Skills.In the Employee entity I used #JsonIgnore annotation to avoid the reccursion. But when I inserted the values Employee table got updated but the joining tabled is not updating.
This is my Employee entity class
#Entity
#Table(name = "Employee")
public class Employee implements Serializable{
private static final long serialVersionUID = -3009157732242241606L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long emp_id;
#Column(name = "emp_fname")
private String emp_fname;
#Column(name = "emp_lname")
private String emp_lname;
#Column(name = "emp_email")
private String emp_email;
#Column(name = "emp_dob")
private Date emp_dob;
#ManyToMany(cascade = CascadeType.MERGE)
#JoinTable(name = "emp_skills",
joinColumns = #JoinColumn(name = "emp_id", referencedColumnName = "emp_id"),
inverseJoinColumns = #JoinColumn(name = "s_id",referencedColumnName = "s_id"))
#JsonIgnore
private Set<Skills> skills;
}
This is my Skills class
#Entity
#Table(name = "Skills")
public class Skills implements Serializable {
private static final long serialVersionUID = -3009157732242241606L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long s_id;
#Column(name = "s_name")
private String s_name;
#ManyToMany(mappedBy = "skills")
private Set<Employee> employees;
And this is my controller class method to save data
#RequestMapping("/save")
#PostMapping("/save")
#CrossOrigin
public void createEmployee(#RequestBody Employee employee, BindingResult bindingResult){
Employee emp = new Employee(employee.getEmp_fname(),employee.getEmp_lname(),employee.getEmp_email(),employee.getEmp_dob());
emp.setSkills(employee.getSkills());
empRepository.save(emp);
//empRepository.save(new Employee(employee.getEmp_fname(),employee.getEmp_lname(),employee.getEmp_email(),employee.getEmp_dob()));
}
I want to update both Employee and emp_skills (the joining table) when the save method is triggered.

path expected for join JPA Hibernate MySQL

I'm using composite PK in my app with 2 tables and one joining table.
I wrote this query for function:
#Repository
public interface HospitalDoctorDao extends JpaRepository<HospitalDoctor, Integer>{
#Query("select hd from HospitalDoctor hd join hospital on hd.hospital_id=hospital.id join doctor on hd.doctor_id = doctor.id where hospital_id = ?1 and doctor_id = ?1")
HospitalDoctor findByHospitalIdAndDoctorId(int hospital_id, int doctor_id);
}
and I am getting error Path expected for file! In MySQL everything is working. How Hibernate works in this case? How I should write this query? Here is my #Entity of join table:
#Entity
#Table(name = "hospital_doctor")
public class HospitalDoctor {
#Embeddable
static class HosdocPK implements Serializable {
private int hospitalId;
private int doctorId;
}
#EmbeddedId
#JsonBackReference
public HosdocPK hosdocPK;
#JsonManagedReference
#MapsId("DoctorId")
#ManyToOne(optional = false)
#JoinColumn(name = "doctorId", referencedColumnName = "id")
private Doctor doctor;
#JsonManagedReference
#MapsId("HospitalId")
#ManyToOne(optional = false)
#JoinColumn(name = "hospitalId", referencedColumnName = "id")
private Hospital hospital;
#Column(name = "Id")
private int id;
#Temporal(TemporalType.DATE)
private Date contract_start_date;
#Temporal(TemporalType.DATE)
private Date contract_end_date;
private String position;
private String supervisor;
private boolean part_time;
Getters and setters
}
Your query is incorrect.
Try:
select hd from HospitalDoctor hd where hd.hospital.id = ?1 and hd.doctor.id = ?2

Hibernate multiple subqueries with DetachedCriteria

I would like write this query into HQL :
select DISTINCT * from transportation transp
inner join price p on p.transportationId = transp.transportationId
where p.sectionId = ( select sec.sectionId from section sec where sec.lineId = ( select l.lineId from line l where l.lineId = 1000000000) )
But don't know write subqueries. I know I must use DetachedCriteria.
An other question:
If we can write this query in native query (using createSQLQuery), how can cast returned objet to Transportation entity ?
Thanks
My entities :
#Entity
#Table(name = "transportation")
public class Transportation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "transportationId")
private Integer id;
#OneToMany(mappedBy = "transportation", fetch = FetchType.EAGER)
#JsonBackReference(value = "price-transportation")
private Set<Price> prices = new HashSet<Price>();
...
}
#Entity
#Table(name = "price")
public class Price implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "priceId")
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "transportationId")
#JsonManagedReference(value = "price-transportation")
private Transportation transportation;
...
}
#Entity
#Table(name = "section")
public class Section implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sectionId")
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "lineId")
#JsonManagedReference
private Line line;
...
}
#Entity
#Table(name = "line")
public class Line implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "lineId")
private Integer id;
#OneToMany(mappedBy = "line", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JsonBackReference
private Set<Section> sections = new HashSet<Section>();
...
}
I solved my issue by using .addEntity(Transportation.class) like this :
String query = "select DISTINCT * from moyen_transport transp"
+ " join prix_voyage p on p.ID_MoyenTransport = transp.ID_MoyenTransport"
+ " where p.ID_Troncon = ( select t.ID_Troncon from troncon t where t.ID_Troncon = ( select l.ID_Ligne from ligne l where l.ID_Ligne = 1000000000) )";
Query result = getSession().createSQLQuery(query).addEntity(Transportation.class)**;
List<Transportation> results = result.list();

Named query join select

I need to get GroupEntity objects which have assigned specific role in RoleGroupEntity Table.
I try to do this like that:
#NamedQuery(name = "GroupEntity.getGIDs", query = "SELECT o FROM RoleGroupEntity u JOIN FETCH u.GroupId o WHERE u.role_id LIKE :role_id")
but I got:
org.hibernate.QueryException: could not resolve property: role_id of: RoleGroupEntity
Entites sample:
#Entity
#Table(name = "group")
public class GroupEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "gid_number")
private Long gid_number;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "GroupId")
private List<RoleGroupEntity> GroupId;
RoleGroupEntity has Composite Key:
#Entity
#Table(name = "role_group")
public class RoleGroupEntity implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private RoleGroupCompositeKey posRGKey;
#MapsId("role_id")
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "role_id")
private RoleEntity roles;
#MapsId("group_id")
#ManyToOne
#JoinColumn(name = "group_id")
private GroupEntity GroupId;
Do you know how to make my select query to work?
You can not use the joincolumn you have to use: u.roles.id LIKE :role_id")
#NamedQuery(name = "GroupEntity.getGIDs", query = "SELECT o FROM RoleGroupEntity u JOIN FETCH u.GroupId o WHERE u.roles.id LIKE :role_id")

Converting SQL query to JPA NamedQuery

I'm trying to implement a Keyword search functionality that returns a List of Keyword entities based on a field text match.
Right now, the query
select * from photo_keywords pk
inner join keywords k on pk.photo_id = k.keyword_id
inner join photos p on pk.keyword_id = p.photo_id
where k.keyword LIKE "%$SOME_SEARCH_VALUE%";
returns all matching photos for a given keyword search. I'd like to have this adapted to a #NamedQuery with the following Entity objects:
#Entity
#Table(name = "keywords")
public class Keyword implements Serializable{
#Id
#Column(name = "keyword_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String keyword;
#ManyToMany(mappedBy = "keywords")
private List<Photo> photos;
//getters and setters
}
and
#Entity
#Table(name = "photos")
public class Photo implements Serializable{
#Id
#Column(name = "photo_id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "photo_name", nullable = false)
private String photoName;
#Column(name = "photo_path", nullable = false)
private String photoPath;
#Column(name = "upload_date", nullable = false)
private Date uploadDate;
#Column(name = "view_count", nullable = false)
private int viewCount;
#Column(name = "capture_date", nullable = false)
private Date captureDate;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "photo_metadata")
#MapKeyColumn(name = "metadata_name")
#Column(name = "metadata_value")
private Map<String, String> photoMetadata;
#ManyToMany
#JoinTable(name = "photo_keywords",
joinColumns = #JoinColumn(name = "keyword_id"),
inverseJoinColumns = #JoinColumn(name = "photo_id"))
public List<Keyword> keywords;
//getters and setters
}
This creates a join table photo_keywords, rather than a JoinColumn.
What I've tried so far with the Keyword entity:
#NamedQueries({
#NamedQuery(
name = "findKeywordByName",
query = "SELECT keyword from Keyword k WHERE k.keyword = :keyword"
)
})
which is executed via
public Keyword findKeywordByString(String keyword){
Keyword thisKeyword;
Query queryKeywordExistsByName = getEntityManager().createNamedQuery("findKeywordByName");
queryKeywordExistsByName.setParameter("keyword", keyword);
try {
thisKeyword = new Keyword((String) queryKeywordExistsByName.getSingleResult());
} catch (NoResultException e){
thisKeyword = null;
}
return thisKeyword;
}
This returns the Keyword, but with the photos property being null. This is to be expected, since I'm only selecting the keyword property. How can I adapt the SQL query above to a #NamedQuery?