Can't get result when running the query from Spring Data Jpa - postgresql

When running the following query in pgAdmin, everything is good but when I run the query from java code i get an error.
I tried to cast the variables but no result, I get an error of cast syntax
The query interface:
public interface SeanceRepository extends JpaRepository<Seance, Integer>{
#Query(value = "select * from seance, patient where extract(month from date) = ?1 "
+ "and extract(year from date) = ?2 and patient.id = seance.patient_id",
nativeQuery = true)
public List<Object> getSeanceByMonthYear(String month, String year);
}
The error :
org.postgresql.util.PSQLException: ERREUR: l'opérateur n'existe pas : double precision = character varying
Indice : Aucun opérateur ne correspond au nom donné et aux types d'arguments.
Vous devez ajouter des conversions explicites de type.
Position : 62
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2440) ~[postgresql-42.2.5.jar:42.2.5]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2183) ~[postgresql-42.2.5.jar:42.2.5]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:308) ~[postgresql-42.2.5.jar:42.2.5]
Patient.java
#Entity
#Table(name = "Patient")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Patient {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String firstName;
private String lastName;
private String cin;
private Date birthDate;
private String phoneNumber;
private Boolean active;
//getters and setters
}
seance.java
#Entity
#Table(name = "Seance")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Seance {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private Date date;
#OneToOne
private Patient patient;
#OneToOne
private TypeConsultation typeConsultation;
private String motif;
//getters and setters

It is because the function extract a double and you compare it to a string

As you can see in https://w3resource.com/PostgreSQL/extract-function.php
The extract function() is used to retrieves subfields such as year or
hour from date/time values. The source must be a value expression of
type timestamp, time, or interval. The field is an identifier or
string that selects what field to be extracted from the source value.
Syntax:
extract(field from timestamp) or extract(field from interval)
Return Type: double precision.
PostgreSQL Version: 9.3
extract returns a value in double presision and you try to compare it to a varchar. It can not be done by postgresSQL automatically, you have to do it explicitly:
#Query(value = "select * from seance, patient where extract(month from date)::varchar(255) = ?1 "
+ "and extract(year from date)::varchar(255) = ?2 and patient.id = seance.patient_id",
nativeQuery = true)

Related

Which return value should I use for the one-to-one table when using spring boot jpa?

We are working on a club management project.
There is a club president on the club table and the user ID is received as a foreign key.
I want to join two tables while using jpa and get the results
If you specify the mapped club table as a type, an error appears (image 1)
If you interface the resulting field, only null values are returned. (Image 2)
How shall I do it?
(Image1)
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object[]] to type [#org.springframework.data.jpa.repository.Query com.wodongso.wodongso.entity.Society] for value '{호남대학교, 왕유저13, 두 발의 자유1, 스포츠, 두 바퀴만 있다면 지원가능!!1, 허벅지 터지도록 활동합니다1, true}'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [#org.springframework.data.jpa.repository.Query com.wodongso.wodongso.entity.Society]
(Image2)
society entity
user entity
#Entity
#Data
public class User {
#Id
private String id;
private String name;
private String nickname;
private String password;
private String role;
private String contact;
#Column(name = "profile_url")
private String profileUrl;
private String region;
private String university;
private String major;
#Column(name = "class_of")
private Integer classOf;
private boolean enabled;
#Column(name = "created_at")
private Date createdAt;
}
SocietyRepository
#Repository
public interface SocietyRepository extends JpaRepository<Society, Integer> {
Page<Society> findByNameContaining(String searchKeyword, Pageable pageable);
#Query("SELECT s FROM Society s WHERE s.enabled = :isEnable")
Page<Society> findByEnabledPage(#Param("isEnable") boolean isEnable, Pageable pageable);
#Query("SELECT u.university, u.name, s.name, s.category, s.simpleDesc, s.detailDesc, s.enabled " +
"FROM Society s " +
"INNER join User u " +
"ON u.id = s.officerId " +
"WHERE u.university = :university")
List<Society> findAllByUniversity(#Param("university") String university);
}
Create a class which contains all the fields and add an all args constructor and than use the query:
#Query("SELECT new SocietyWithUser(u.university, u.name, s.name, s.category, s.simpleDesc, s.detailDesc, s.enabled) " +
"FROM Society s " +
"INNER join User u " +
"ON u.id = s.officerId " +
"WHERE u.university = :university")
List<SocietyWithUser> findAllByUniversity(#Param("university") String university);

How to return a count column not exists in table by JPA

I want find a way to get extra column that count my records and return it in 1 mapping entity with extra filed.
I tried #transient on field but it will not return value when query.
Then I remove #transient but get an exception when save.
Also I tried #Formula but received null pointer exception.
Here's my repository code:
#Query(value = "select id,account,session_id,create_time,count from query_history a join " +
"(select session_id sessionId,max(create_time) createTime,count(*) count from query_history group by session_id) b " +
"on a.session_id = b.sessionId and a.create_time = b.createTime where account = ?1 order by create_time desc",
countQuery = "select count(distinct(session_id)) from query_history where account = ?1",
nativeQuery = true)
Page<QueryHistory> findByNtAndGroupBySessionAndAction(String account, Pageable pageable);
entity code:
#Entity
#Table(name = "query_history")
#Data
public class QueryHistory {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String account;
#Column
private Long sessionId;
#Column
private long createTime;
#Transient
private Integer count;
}
Sorry about my English and thanks a lot for any advice.
I solved the problem by projections spring-data-projections, in fact I tried this before but in my sql:
select id,account,session_id,create_time,count
which should be:
select id,account,session_id sessionId,create_time createTime,count
PS:
projection interface:
public interface QueryHistoryWithCountProjection {
Long getId();
String getAccount();
Long getSessionId();
long getCreateTime();
Integer getCount();
}

Composite key query in JPQL not generated correctly

I use spring data jpa and I use composite key
#Entity
#IdClass(SamplesPK.class)
public class Samples extends BaseEntity {
#Id
private String sampleLetter;
#Embedded
private TestSamples testSamples;
#Id
#ManyToOne(optional=false)
#JoinColumns({
#JoinColumn(name = "sampling_id", referencedColumnName = "id"),
#JoinColumn(name = "sampling_year", referencedColumnName = "year")})
private Samplings sampling;
//get set
}
public class SamplesPK implements Serializable {
private SamplingsPK sampling;
private String sampleLetter;
public SamplesPK(SamplingsPK sampling, String sampleLetter) {
this.sampling = sampling;
this.sampleLetter = sampleLetter;
}
//get set
}
#Entity
#IdClass(SamplingsPK.class)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Samplings {
#Id
private Integer year;
#Id
#GeneratedValue
private Integer id;
#OneToMany(mappedBy = "sampling", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Samples> samples = new ArrayList<>();
//get set
}
public class SamplingsPK implements Serializable {
private int year;
private Integer id;
public SamplingsPK(int year, Integer id) {
this.id = id;
this.year = year;
}
}
I try to do search sample with composite key
#Query(value = "select s from Samples s Join fetch s.sampling sp Join fetch sp.product p Join fetch p.productType Join Fetch s.testSamples.compressionTest where s.id=:id and s.year=:year and s.sampleLetter=:sampleLetter and sp.id=:id and sp.year=:year")
public Samples findSamplesWithFullProductAndTest(#Param("id") Integer id, #Param("year") Integer year, #Param("sampleLetter") String sampleLetter);
I get this error
java.lang.IllegalArgumentException: Parameter value [2] did not match
expected type [com.lcm.model.SamplesPK (n/a)]
Edit,
I modified query to
select s from Samples s Join fetch s.sampling sp Join fetch sp.product p Join fetch p.productType Join Fetch s.testSamples.compressionTest where s.sampling.id=:id and s.sampling.year=:year and s.sampleLetter=:sampleLetter and sp.id=:id and sp.year=:year
but I get this error
org.postgresql.util.PSQLException: ERROR: operator does not exist:
record = integer Indice : No operator matches the given name and
argument type(s). You might need to add explicit type casts.
Generated query is
select
samples0_.sample_letter as sample_l1_20_0_,
samples0_.sampling_id as sampling0_20_0_,
samplings1_.id as id2_21_1_,
samplings1_.year as year3_21_1_,
products2_.id as id2_15_2_,
producttyp3_.id as id1_16_3_,
compressio4_.id as id1_3_4_,
samples0_.sampling_id as samplin27_20_0_,
samples0_.sampling_year as samplin28_20_0_,
samples0_.compression as compres18_20_0_,
samples0_.compression_number as compres19_20_0_,
samples0_.compression_test_id as compres29_20_0_,
samplings1_.available_for_test as availabl4_21_1_,
samplings1_.dtype as dtype1_21_1_,
products2_.created_at as created_3_15_2_,
products2_.updated_at as updated_4_15_2_,
products2_.name_en as name_en5_15_2_,
products2_.dtype as dtype1_15_2_,
producttyp3_.created_at as created_2_16_3_,
producttyp3_.updated_at as updated_3_16_3_,
producttyp3_.name_en as name_en4_16_3_,
compressio4_.created_at as created_2_3_4_,
compressio4_.updated_at as updated_3_3_4_
from
permacon.samples samples0_
inner join
permacon.samplings samplings1_
on samples0_.sampling_id=samplings1_.id
and samples0_.sampling_year=samplings1_.year
inner join
permacon.products products2_
on samplings1_.product_id=products2_.id
inner join
permacon.product_types producttyp3_
on products2_.product_type_id=producttyp3_.id
inner join
permacon.compressions compressio4_
on samples0_.compression_test_id=compressio4_.id
where
(
samples0_.sampling_id, samples0_.sampling_year
)=?
and samplings1_.year=?
and samples0_.sample_letter=?
and samplings1_.id=?
and samplings1_.year=?
Edit 2
#MappedSuperclass
public abstract class BaseEntity {
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
//get set...
}
Inheritance is used because I have two table who extends Samplings
you year field is a int put int instead of Integer in your
findSamplesWithFullProductAndTest
method

JPA with hibernate implementation is generating wrong named query

I configured JPA with spring. I am using spring 4.
I have an entity
#Entity
#NamedQueries({
#NamedQuery(name="PartnerCourseMapping.findByPartnerCourseIdAndHandlerName", query="select pm from PartnerCourseMapping pm where pm.partnerCourseId=:partnerCourseId and pm.handlerName=:handlerName")
})
#Table(name="PARTNER_COURSE_MAPPING")
public class PartnerCourseMapping implements Serializable {
private static final long serialVersionUID = 1L;
#Id
protected Long id;
#Column(name="COURSE_ID")
protected Long courseId;
#Column(name="PARTNER_COURSE_ID")
protected String partnerCourseId;
#Column(name="PARTNER_ID")
protected Integer partnerId;
#Column(name="PRODUCT_TYPE")
protected String productType;
#Column(name="HANDLER_NAME")
protected String handlerName;
//getters and setters
}
I have another entity which i defined like below
#Entity
#NamedNativeQueries({
#NamedNativeQuery(
name="ExternalCourse.findExternalCourseMappingByLearningSessionGuid",
query="SELECT PCM.*, LE.id AS LearnerEnrollmentId, LE.LEARNER_ID AS LearnerId "
+ "FROM LEARNINGSESSION LS "
+ "INNER JOIN LEARNERENROLLMENT LE ON LE.ID = LS.ENROLLMENT_ID "
+ "INNER JOIN PARTNER_COURSE_MAPPING PCM ON PCM.COURSE_ID = LE.COURSE_ID "
+ "WHERE LS.LEARNINGSESSIONGUID = :learningSessionGuid",
resultSetMapping="externalCourseMapping"
)
})
#SqlResultSetMappings({
#SqlResultSetMapping(
name="externalCourseMapping",
classes = {
#ConstructorResult(targetClass = ExternalCourse.class,
columns={
#ColumnResult(name = "ID", type=Long.class ),
// remaing ColumnResult
}
)
}
)
})
public class ExternalCourse extends PartnerCourseMapping /*implements Serializable*/ {
private Long learnerEnrollmentId;
private Long learnerId;
//default constructor
public ExternalCourse(Long id, Long courseId, String partnerCourseId, Integer partnerId, String productType,
String handlerName, Long learnerEnrollmentId, Long learnerId) {
this.id = id;
// remaing values
}
//getters and setters for learnerEnrollmentId and learnerId
}
Now I query PartnerCourseMapping.findByPartnerCourseIdAndHandlerName
TypedQuery<PartnerCourseMapping> query = entityManager.createNamedQuery("PartnerCourseMapping.findByPartnerCourseIdAndHandlerName", PartnerCourseMapping.class);
query.setParameter("partnerCourseId", paernerCourseId);
query.setParameter("handlerName", handlerName);
return getResult(query);
protected T getResult(TypedQuery<T> query) {
List<T> list = query.getResultList();
return CollectionUtils.isEmpty(list) ? null : list.get(0);
}
Hibernate is generating exception that
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
...
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid column name 'learnerEnrollmentId'.
When I debug then I saw hibernate is generating query like below
select partnercou0_.id as id2_13_,
partnercou0_.COURSE_ID as COURSE_I3_13_,
partnercou0_.HANDLER_NAME as HANDLER_4_13_,
partnercou0_.PARTNER_COURSE_ID as PARTNER_5_13_,
partnercou0_.PARTNER_ID as PARTNER_6_13_,
partnercou0_.PRODUCT_TYPE as PRODUCT_7_13_,
partnercou0_.learnerEnrollmentId as learnerE8_13_,
partnercou0_.learnerId as learnerI9_13_,
partnercou0_.DTYPE as DTYPE1_13_
from PARTNER_COURSE_MAPPING partnercou0_ where partnercou0_.PARTNER_COURSE_ID=? and partnercou0_.HANDLER_NAME=?
I want to ask that why hibernate is including learnerEnrollmentId and learnerId column? I am passing the query name and query. If I refactor my code like below then I get the correct result
#Entity
#NamedNativeQueries({
#NamedNativeQuery(
name="ExternalCourse.findExternalCourseMappingByLearningSessionGuid",
...
resultSetMapping="externalCourseMapping"
)
})
#SqlResultSetMappings({
#SqlResultSetMapping(
name="externalCourseMapping",
classes = {
..
}
)
})
public class ExternalCourse implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
private Long courseId;
private String partnerCourseId;
private Integer partnerId;
private String productType;
private String handlerName;
private Long learnerEnrollmentId;
private Long learnerId;
//default constructor
//constructor with all parameters
//getters and setters
}
Why I am getting exception when I am extending class? I am passing the query name. Why ?
Thanks

Using COUNT in JPQL Query

I have the following JPQL query:
List<DestinationInfo> destinations = em.createQuery("SELECT NEW com.realdolmen.patuva.dto.DestinationInfo(d.name, d.continent, MIN(t.departureDate), MIN(t.pricePerDay), COUNT(t.id))" +
" FROM Destination d, Trip t" +
" WHERE d.continent = :continent " +
" GROUP BY d.name, d.continent").setParameter("continent", searchedContinent).getResultList();
If I run this I get the error:
javax.ejb.EJBTransactionRolledbackException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [com.realdolmen.patuva.dto.DestinationsList]
If I leave out the COUNT(t.id) and remove that parameter from my DestinationInfo constructor it works fine. Why can't I map the COUNT(t.id) to my DestinationInfo DTO.
This is my DestinationInfo class:
public class DestinationInfo {
private String name;
private Continent continent;
private Date earliestDeparture;
private Integer totalNumTrips;
private BigDecimal lowestPrice;
public DestinationInfo(String name, Continent continent, Date earliestDeparture, BigDecimal lowestPrice, Integer totalNumTrips) {
this.name = name;
this.continent = continent;
this.earliestDeparture = earliestDeparture;
this.totalNumTrips = totalNumTrips;
this.lowestPrice = lowestPrice;
}
// getters and setters
}
Apparently COUNT(t.id) returns a number of type long. Changing the DestinationInfo class to the following makes it work:
public class DestinationInfo {
private String name;
private Continent continent;
private Date earliestDeparture;
private long totalNumTrips;
private BigDecimal lowestPrice;
public DestinationInfo(String name, Continent continent, Date earliestDeparture, BigDecimal lowestPrice, long totalNumTrips) {
this.name = name;
this.continent = continent;
this.earliestDeparture = earliestDeparture;
this.totalNumTrips = totalNumTrips;
this.lowestPrice = lowestPrice;
}
// getters and setters
}