How do you use the JPA #Query notation? I wish to run the query:
SELECT region, winner_count
FROM awards_regions
WHERE award_id = ?
ORDER BY region
I have the repository:
public interface AwardsRegionsRepository extends JpaRepository<AwardRegion,AwardRegionPk>{
List<AwardRegion> findAllByOrderByAwardRegionPk_RegionAscSortKeyAsc();
List<AwardRegion> findByAwardRegionPk_RegionOrderBySortKeyAsc(String region);
#Query("select a.region, a.winner_count from awards_regions a "
+ "where a.award_id = :awardId order by a.region")
List<AwardRegion> findByAwardRegionPk_AwardId(#Param("awardId") Long awardId);
}
My entity Java beans are
#Entity
public class AwardRegion implements Serializable{
#EmbeddedId
private AwardRegionPk awardRegionPk;
#Column(name = "award")
private String award;
#Column(name = "sort_key")
private String sortKey;
#Column(name = "winner_count")
private String winnerCount;
}
...and embedded PK
#Embeddable
public class AwardRegionPk implements Serializable{
#Column(name = "region")
private String region;
#Column(name = "award_id")
private Long awardId;
}
It looks as though you are using the database table column names in your JPA query. Use the Java bean names.
public interface AwardsRegionsRepository extends JpaRepository<AwardRegion,AwardRegionPk>{
List<AwardRegion> findAllByOrderByAwardRegionPk_RegionAscSortKeyAsc();
List<AwardRegion> findByAwardRegionPk_RegionOrderBySortKeyAsc(String region);
#Query("select a.awardRegionPk.region, a.winnerCount from AwardRegion a "
+ "where a.awardRegionPk.awardId = :awardId order by a.awardRegionPk.region")
List<AwardRegion> findByAwardRegionPk_AwardId(#Param("awardId") Long awardId);
}
Related
So I have 4 tables
An Employer
#Entity
#EqualsAndHashCode(callSuper = false)
#Table(name = "employers")
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "jobPostings"})
#PrimaryKeyJoinColumn(name="employer_id", referencedColumnName = "id")
public class Employer extends User {
#Column(name = "company_name")
private String companyName;
#Column(name = "website")
private String website;
#Column(name = "phone_number")
private String phoneNumber;
#OneToMany(mappedBy="employer")
private List<JobPosting> jobPostings;
}
A City
#Data
#Entity
#Table(name="cities")
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "jobPostings"})
public class City {
#Id
#Column(name="id")
private int id;
#Column(name="city_name")
private String cityName;
#OneToMany(mappedBy="city")
private List<JobPosting> jobPostings;
}
A Job Position
#AllArgsConstructor
#Data
#Entity
#Table(name="job_positions")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "jobPostings"})
public class JobPosition {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="job_position_id")
private int id;
#Column(name="title")
private String title;
#OneToMany(mappedBy="jobPosition")
private List<JobPosting> jobPostings;
}
And A JobPosting(like a job advertisement)
#Entity
#Table(name="job_postings")
#Data
#NoArgsConstructor
#AllArgsConstructor
//#JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "city", "jobPosition","employer"})
public class JobPosting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="job_requirements")
private String jobRequirements;
#Column(name="salary_min")
private int salaryMin;
#Column(name="salary_max")
private int salaryMax;
#Column(name="application_deadline")
private LocalDate applicationDeadline;
#Column(name="number_of_openings")
private int numberOfOpenings;
#Column(name="stream_date")
private LocalDate streamDate;
#ManyToOne()
#JoinColumn(name="city_id")
private City city;
#ManyToOne()
#JoinColumn(name="job_position_id")
private JobPosition jobPosition;
#ManyToOne()
#JoinColumn(name= "employer_id")
private Employer employer;
}
I have implemented the necessary mapping for all of them and it is working fine.
However, I want to Join them in a DTO like:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class JobPostingWithJobPositionCityEmployerDto {
private int id;
private String jobRequirements;
private int salaryMin;
private int salaryMax;
private LocalDate applicationDeadline;
private int numberOfOpenings;
private LocalDate streamDate;
private String cityName;
private String title;
private String companyName;
}
to get the fields I want in a more clean way, I am trying to use #Query annotation of springframework.jpa but I can not quite manage it since I just learned about this, the query I am using is:
#Query(value ="Select new kodlamaio.hrms.entities.dtos.JobPostingWithJobPositionCityEmployerDto"
+ "(j.id, j.jobRequirements, j.salaryMin, j.salaryMax, j.numberOfOpenings, j.streamDate, j.applicationDeadline, c.cityName, p.title, e.companyName)"
+ " From Employer e Inner Join e.jobPostings j, "
+ "From City c Inner Join c.jobPostings j, "
+ "From JobPosition p Inner Join p.jobPostings j", nativeQuery = true)
List<JobPostingWithJobPositionCityEmployerDto> getJobPostings();
I dont even know if this is the correct way to do this, I keep getting syntax error, I looked up answers but couldnt quite grasp what they were saying, there were a lot of different scenarios.
So if anybody could help me with this Query and recommend some sources to learn about different commands, I would appreciate it so much, Thanks in advance.
Mapping the result of a query with a DTO using the new keyword in a query only works for JPQL, it will not work for SQL (which is what you are using).
It also looks to me if you are trying to write a too complex query as everything can be achieved/reached through the JobPosting class, which will implicitly do the join when using JPQL.
So instead of your native SQL writing a JPQL should fix it.
Something like
#Query(value ="Select new kodlamaio.hrms.entities.dtos.JobPostingWithJobPositionCityEmployerDto"
+ "(jp.id, jp.jobRequirements, jp.salaryMin, jp.salaryMax, jp.numberOfOpenings, jp.streamDate, jp.applicationDeadline, jp.city.cityName, jp.jobPosition.title, jp. employer.companyName)"
+ " From JobPosting jp)
Which should do the trick. Your JPA provider should be smart enough to figure out what to join and retrieve.
Generaly this is named Projection, I believe that you have already created JobPostingWithJobPositionCityEmployerDto with a constructor of 10 args, with their respective data type of course. And since it is custom to jpa you can't use nativeQuery = true. These modifications should be fine.
#vlad-mihalcea to the rescue
https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/
I have a JPA repository for a DB entity as follows:
#Repository
public interface StudentRepository
extends JpaRepository<Student, String> {
}
Student entity is as follows:
#Entity
#Table(name = "student")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "custom-uuid")
#GenericGenerator(name = "custom-uuid",
strategy = "generator.CustomUUIDGenerator")
private String id;
#Column(name = "roll_number")
private String rollNumber;
#Column(name = "name")
private String name;
#LastModifiedDate
#Column(name = "last_modified_date")
#JsonIgnore
private Instant lastModifiedDate = Instant.now();
Now, I would like to write the following SQL query using JPA as follows:
SELECT id, roll_number from student where id=<id> order by last_modified_date desc;
Being new to JPA/Hibernate, I don't have an idea how to achieve this using JPA/Hibernate.
Could anyone please help here ?
You could write something like:
String hql = "SELECT s.id, s.rollNumber FROM Student s WHERE s.id = :id ORDER BY s.lastModifiedDate DESC";
query.setParameter("id", 10);
Query query = session.createQuery(hql);
List results = query.list();
Refer: https://www.tutorialspoint.com/jpa/jpa_jpql.htm
Create a new method in Repository
#Repository
public interface StudentRepository extends JpaRepository<Student, String> {
/**
* List all student by criterias.
*
* #return
*/
#Query(value = "SELECT id, roll_number from student where id=?1 order by last_modified_date desc;", nativeQuery = true)
List<Student> listStudent(String id);
}
Reference document: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
I am developing an application that allows managing candidates in a company, for that I use spring-boot, in order to select the employees who master such a technology (Techno) I used a request JPQL.
So, How can I find a candidate by techno?
In my project I used this code:
1 - the class candidat.java
#Entity
public class Candidat {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "candidat_id")
private int id;
private String nom;
private String prenom;
private String ville;
private int numTel;
private String mail;
private String pseudo;
private String roleCible;
private String typeContrat;
private String villeRecherchee;
#OneToMany(mappedBy="candidat")
private List<Techno> techno;
#Temporal(TemporalType.DATE)
private Date date;
#OneToMany
private List<SecteurActivites> secteurActivites;
public Candidat() {
// TODO Auto-generated constructor stub
}
2- the class Techno.java
#Entity
public class Techno {
#Id
#GeneratedValue
#Column(name = "techno_id")
private int id ;
private String nomTechno;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "candidat_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Candidat candidat;
public Techno() {
// TODO Auto-generated constructor stub
}
/**
* #param nomTechno
* #param candidat
*/
public Techno(String nomTechno, Candidat candidat) {
super();
this.nomTechno = nomTechno;
this.candidat = candidat;
}
3- My CandidatController
#GetMapping(value = "/GetAllCandidats/{nomTechno}")
public List<Candidat> afficherCandidat(#PathVariable ("nomTechno") String nomTechno){
return candidatdao.findByTechno(nomTechno);
}
4- the repository:
#Repository
public interface CandidatDao extends JpaRepository <Candidat, String>{
List<Candidat> findByDate(Date date);
#Query("SELECT DISTINCT e FROM Candidat e INNER JOIN e.Techno t")
List<Candidat> findByTechno(String nomTechno);
}
5- app.properties
server.port= 9090
spring.jpa.show-sql = true
spring.datasource.url= jdbc:mysql://localhost:3306/database
spring.datasource.username=??
spring.datasource.password=??
spring.jpa.hibernate.ddl-auto=update
The result in console is:
"Validation failed for query for method public abstract java.util.List com.avatar.dao.CandidatDao.findByTechno(java.lang.String)!"
You can declare the following method into your JpaRepository (also remove the #Query, it is not needed).
List<Candidat> findDistinctByTechnoNomTechno(String nomTechno);
Also in Techno.java you should add the #Column annotation and map it with the DB schema.
I am not sure if you have pasted incomplete code of your entities on purpose. If not your entities are not correct. You should create setters/getters as the following
private String nomTechno;
#Column(name = "NOM_TECHNO")
public String getNomTechno() {
return nomTechno;
}
public void setNomTechno(String nomTechno){
this.nomTechno = nomTechno;
}
Do the above for all variables in your entities.
You do not need to add explicit #Query for this, Spring data can formulate a query if you have right method names
Instead of
#Query("SELECT DISTINCT e FROM Candidat e INNER JOIN e.Techno t")
List<Candidat> findByTechno(String nomTechno);
Try this
List<Candidat> findDistinctByTechno_NomTechno(String nomTechno);
trying to run a native query however I'm getting The column name sb_modelid is not valid. when attempting to map the return object to my model object in java? I have verified all the column names are correct.
1) Why is it referring to my column name as sb_modelid and not sbModelID?
2) Why is not being mapped to my POJO correctly?
Thanks!
Model Object:
package com.dish.wfm.linkingTickets.model.repository;
public class Model {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "sbModelID")
private Long sbModelId;
#Column(name = "modelID")
private String modelID;
#Column(name = "serialNumber")
private String serialNumber;
#Column(name = "serviceContractNumber")
private String serviceContractNumber;
}
Repo:
#Repository
public interface SBModelRepo extends JpaRepository<Model, Long> {
#Query(value = "select m.sbModelID, m.modelID, m.serialNumber, m.serviceContractNumber from sb.Model m where m.modelID = ?1 and m.serialNumber = ?2", nativeQuery = true)
Model findTopByModelIDAndSerialNumber(String modelID, String serialNumber);
}
I am using Spring-Boot with JPA and a MySQL backend. Now I got quite confused about the repositories Spring-Boot provides. I know these are quite powerful (and seem to be quite useful since they can shorten your code a lot). Still, I do not understand how to represent Joins within them, since the result-set should be a combination of specified attributes in the select of a few Entities.
Now let's assume we have three tables Book, Author, AuthorOfBook, where the last one is simply connecting Book and Author by a combined Primary key. I guess we had the following Java-Classes:
Entity Book:
#Entity
#Table(name="BOOK")
public class Book {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "TITLE")
private String title;
}
Entity Author
#Entity
#Table(name="AUTHOR")
public class Author {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "FIRSTNAME")
private String firstname;
//Let's assume some getters and setters and a constructor
}
Entity AuthorOfBook:
#Entity
#Table(name="BOOK")
public class Book {
#EmbeddedId
private AuthorOfBookId pk;
}
An Embedded ID
#Embeddable
public class AuthorOfBookId implements Serializable {
private int authorId;
private int bookId;
}
Repository
#Repository
public interface AuthorOfBookRepository extends JpaRepository<,AuthorOfBookId> {
}
Now how would I represent that query:
SELECT b.name, a.firstname, a.lastname from AuthorOfBook ab inner join Book b on b.id = ab.book_id inner join Author a on a.id = ab.author_id where a.lastname = :lastname;
in my repository? I know the signature would need to be like
#Query([the query string from above])
public (...) findAuthorAndBookByAuthorLastname(#Param("lastname") String lastname);
but I cannot make out what Type the return would be like. What is that method returning? (simply AuthorOfBook would not work I guess)
You don't want AuthorOfBook as a separate Entity. Book should have a field of type Author as a #ManyToOne relationship. That way, given any Book, you can find the author's details.
If you want to handle audits fields you can do something like this:
Audit class
#Embeddable
public class Audit {
#Column(name = "created_on")
private Timestamp createdOn;
#Column(name = "updated_on")
private Timestamp updatedOn;
#Column(name = "is_deleted")
private Boolean isDeleted;
//getters and setters
}
AuditListener to update automatically audits fields
public class AuditListener {
private Long loggedUser = 1001L;
/**
* Method to set the fields createdOn, and isDeleted when an entity is persisted
* #param auditable
*/
#PrePersist
public void setCreatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
if (audit == null) {
audit = new Audit();
auditable.setAudit(audit);
}
audit.setIsDeleted(Boolean.FALSE);
audit.setCreatedOn(Timestamp.from(Instant.now()));
}
/**
* Method to set the fields updatedOn and updatedBy when an entity is updated
* #param auditable
*/
#PreUpdate
public void setUpdatedOn(Auditable auditable) {
Audit audit = auditable.getAudit();
audit.setUpdatedOn(Timestamp.from(Instant.now()));
}
}
And add this to the entities
#EntityListeners(AuditListener.class)
public class Book implements Auditable {
#Embedded
private Audit audit;