Hibernate query for entity with map property - java

I've been struggling with a query in hibernate to update the state of an entity. Such entity, called PaymentRequestLink, is in a one to many relation with another entity called extraparameters
PaymentRequestType.java:
#Entity
#Table(name="payment_link")
public class PaymentRequestLink {
private Map<String, ExtraParameter<E>> extraParameters;
#Fetch(FetchMode.SELECT)
#ElementCollection(fetch=FetchType.EAGER)
#CollectionTable(name="extraparameter_payment_link",
schema=BaseEntity.DATABASE_SCHEMA, joinColumns=#JoinColumn(name="extraparameter_payment_link_id"))
#MapKeyColumn(name = "name", length=64, nullable = false)
public Map<String, ExtraParameter<String>> getExtraParameters() {
return extraParameters;
}
ExtraParameter.java:
#Embeddable
public class ExtraParameter<T extends Serializable> implements Serializable {
//...
#Column(name="extra_type", length=64, nullable=false)
#NotNull
public String getType() {
return type;
}
#Column(name="extra_value", length=255, nullable=false)
#NotNull
public T getValue() {
return value;
}
This is a data example of the extraparameter_payment_link table:
extraparameter_payment_link_id extra_type extra_value name
1 java.sql.Date 2019-01-01 EXPIRATION_DATE
The query I want to make is to update the state of the PaymentRequestLink to EXPIRED when the expiration date, which is stored in the extraparameters, is a date before to the current date.
This is the query I have now:
String stateSentence = "AND state <> '";
String sqlUpdateLinkDetailed = "UPDATE PaymentRequestLink ld SET state='EXPIRED' " +
"WHERE extraParameters.EXPIRATION_DATE.value <= ? " +
stateSentence + PaymentRequestLinkState.PAID;
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 1);
Timestamp now = new Timestamp(calendar.getTimeInMillis());
hibernateTemplate.bulkUpdate(sqlUpdateLinkDetailed, now);
The exception I've got is:
error processing job
org.springframework.orm.hibernate3.HibernateQueryException: could not resolve property: EXPIRATION_DATE of: component[type,value] [UPDATE
com.some.company.PaymentRequestLink ld SET state='EXPIRED' WHERE extraParameters.EXPIRATION_DATE.value <= ? AND state <> 'PAID']; nested exception is org.hibernate.QueryException: could not resolve property: EXPIRATION_DATE of: component[type,value] [UPDATE com.some.company.PaymentRequestLink ld SET state='EXPIRED' WHERE extraParameters.EXPIRATION_DATE.value <= ? AND state <> 'PAID']
Can anyone help me with this?

Elements of indexed collections (arrays, lists, and maps) can be
referred to by index in a where clause only:
String stateSentence = "AND state <> '";
String sqlUpdateLinkDetailed = "UPDATE PaymentRequestLink ld SET state='EXPIRED' " +
"WHERE extraParameters['EXPIRATION_DATE'].value <= ? " +
stateSentence + PaymentRequestLinkState.PAID;
See HQL expressions documentation for details.

Related

How to retrieve data from entity with composed foreign key?

I can't retrieve data from an Entity from my Oracle database.
Config :
Java 8
Hibernate 5.4.20
Jpa 2.2
Oracle11g
My situation :
A JPA Entity Reparation with "classic" data, and an ID from a Vehicule.
A JPA Entity Vehicule stored without a unique ID column because in my table, each vehicule has a period (identify by startDate and endDate) with unique properties.
Example :
id
situation
startDate
endDate
1
EN_USINE
01/01/2020
14/01/2020
1
TRANSFERT
15/01/2020
17/01/2020
1
EN_CONCESSION
18/01/2020
01/03/2020
The primary key of Vehicule is defined by 3 columns : id/startDate/endDate.
I want to get data from Vehicule in the entity Reparation, i got the id of the Vehicule in the table Raparation, and the jointure is done with the date of Reparation that has to be between startDate and endDate in the table Vehicule.
How can i do that ?
#Entity
Public class Vehicule {
#Column(name="id")
String id
#Column(name="startDate")
LocalDate startDate
#Column(name="endDate")
LocalDate endDate
}
#Entity
Public class Reparation {
#Column(name="id_reparation")
String idReparation
#Column(name="date_of_reparation")
LocalDate dateOfReparation
Vehicule vehicule
}
I tried the #joinFormula, but I didn't get it
How would you do that ?
Edit :
I tried a lot of things, like :
#ManyToOne
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula = #JoinFormula(value = "select id from table_vehicule", referencedColumnName = "ID")),
#JoinColumnOrFormula(formula = #JoinFormula(value = "select startDate from table_vehicule where dateOfReparation > startDate", referencedColumnName = "startDate")),
#JoinColumnOrFormula(formula = #JoinFormula(value = "select endDate from table_vehicule where dateOfReparation < endDate", referencedColumnName = "endDate"))
})
Vehicule vehicule;
First thing is ,you can't have an #Entity without providing any #Id to that class ,second if you have an ID composed of multiple fields ,like in your case here ,you make it Embeddable ,and then you declare it in your class as a class member ,here's an example :
#Embeddable
public class MyComposedID {
//Here ,I personaly don't see the usage of id it's neither a surrogate key nor
//used to have any impact on the uniqueness of the Composed Id since you said
//it's uniquely identified by the start and end date
#Column(name="id")
String id;
#Column(name="start_date")
LocalDate startDate;
#Column(name="end_date")
LocalDate endDate;
}
Now you declare it in your Vehicle Entity as an EmbeddedID as follows :
#Entity
Public class Vehicule {
#EmbeddedId
MyComposedID id;
}
As for the query goes , from what i understood ,you want to get the vehicle where the Reparation.reparationDate is between the Vehicle.startDate and Vehicle.endDate,
here's an example with a JPQL query :
Query query = em.createQuery("SELECT v FROM Vehicle v "+
"INNER JOIN Reparation r ON r.reparationDate>= v.id.startDate "+
"AND r.reparationDate<=v.id.endDate");
Hope this helps you .

QuerySyntaxException - unexpected token: a (SQL statement not correct?)

I get following error message when trying to fire an SQl Statement....the exception:
QuerySyntaxException: unexpected token: a near line 1, column 127 [SELECT DISTINCT e FROM com.taqwaapps.entity.Event e, com.taqwaapps.entity.Appointment a WHERE e.eventId = a.event.eventIdĀ AND a.district.city.name = 'Jeddah' ]
It seems that following SQL Statement is not correct:
#Query("SELECT DISTINCT e "
+ "FROM Event e, Appointment a "
+ "WHERE e.eventId = a.event.eventIdĀ "
+ "AND a.district.city.name = 'Jeddah' ")
List<Event> getEventsFiltered();
My Objects are:
#Entity
public class Event {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long eventId;
}
and
#Entity
public class Appointment {
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "eventId")
private Event event;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "districtId")
private District district;
What is wrong?
I found the Problem:
In the past in school time I learned from my informatics Teacher that in SQL it can happen that there is an hidden character which we entered or which got entered but we dont see it. So just write the SQL again using plain writing

Format for a JPA query containing an aggregation and subquery?

I have the following entity (some columns omitted for brevity):
#Entity
#Table(name = "INSTRUCTION")
public class Instruction {
#Id
#Column(name = "ID", nullable = false, unique = true)
public Long id;
#Column(name = "CURRENT_STATUS", nullable = false)
private InstructionState currentStatus;
#Column(name = "SUBTYPE", nullable = false)
private InstructionAction subtype;
//Getters & Setters
}
I want to write the following query in JPA to retrieve a count of the instructions grouped by their CURRENT_STATUS and SUBTYPE. I know that the following SQL works:
SELECT CURRENT_STATUS, SUBTYPE, COUNT(*) count
FROM (SELECT ID, CURRENT_STATUS, SUBTYPE
FROM INSTRUCTION
WHERE VALUE_DATE= '17-JUN-21'
AND LAST_UPDATED >= '16-JUN-21'
AND LAST_UPDATED < '17-JUN-21'
GROUP BY ID, CURRENT_STATUS, SUBTYPE)
GROUP BY CURRENT_STATUS, SUBTYPE;
I want to take the result from this query and map it to a new object call InstructionCount:
public class InstructionCount {
private InstructionState status;
private InstructionAction subType;
private Integer count;
public InstructionCount(final InstructionState status, final InstructionAction subType, final Integer count) {
this.status = status;
this.subType = subType;
this.count = count;
}
//Getters and setters
}
The Problem
I have come up with the following query in JPA for this in my repository class:
#Query(value = "SELECT new com.modles.InstructionCount(CURRENT_STATUS status, SUBTYPE subType, COUNT(*) count) \n" +
"FROM (SELECT ID, CURRENT_STATUS, SUBTYPE \n" +
"\t\tFROM LTD_RTGS_CASHINSTRUCTION \n" +
"\t\tWHERE VALUE_DATE= :valueDate \n" +
"\t\tAND LAST_UPDATED >= :lastUpdatedFrom \n" +
"\t\tAND LAST_UPDATED < :lastUpdatedTo \n" +
"\t\tGROUP BY ID, CURRENT_STATUS, SUBTYPE)\n" +
"GROUP BY CURRENT_STATUS, SUBTYPE", nativeQuery = true)
List<InstructionCount> findInstructionCounts(#Param("valueDate") LocalDate valueDate, #Param("lastUpdatedFrom") LocalDateTime lastUpdatedFrom, #Param("lastUpdatedTo") LocalDateTime lastUpdatedTo);
The issue is that this does not work, and I have found it is because I cannot use the approach of mapping it to a new object using the SELECT new com.modles.InstructionCount with nativeQuery = true. However when I try to remove the nativeQuery = true part and run my test I get the following error:
I also notice that the SQL gets syntax errors in the IDE, highlighted on the second SELECT statement, so I presume there is an issue with this format when not using nativeQuery.
Can anyone help with how I can resolve this issue? I know this can work, because when I remove the SELECT new com.modles.InstructionCount part, it will just return a list of Object[] with the correct values I'm expecting, but I would much prefer to map this to the correct object as part of the query. Alternatively, if there is a way to write this query using the Specification API, I would also use that approach!
Below query should just work just fine and there is no need of your inner/sub query
SELECT CURRENT_STATUS, SUBTYPE, COUNT(ID)
FROM INSTRUCTION
WHERE VALUE_DATE= '17-JUN-21'
AND LAST_UPDATED >= '16-JUN-21'
AND LAST_UPDATED < '17-JUN-21'
GROUP BY CURRENT_STATUS, SUBTYPE;
This should works seemlessly while returning the result as
InstructionCount
------->Edit------------->
#Query(value = "SELECT new com.modles.InstructionCount(currentStatus, subtype, count(id)) FROM Instruction WHERE valueDate= :valueDate AND lastUpdatedFrom >= :lastUpdatedFrom AND lastUpdatedTo < :lastUpdatedTo GROUP BY id, currentStatus, subtype")
List<InstructionCount> findInstructionCounts(#Param("valueDate") LocalDate valueDate, #Param("lastUpdatedFrom") LocalDateTime lastUpdatedFrom, #Param("lastUpdatedTo") LocalDateTime lastUpdatedTo);

How to map a #ManyToOne association to the result of an SQL query

We are working on a migration project and we are migrating from HBM files to annotations.
We are facing repeated column mapping issue when I try to set a value on a property, which basically is an instance of the same class.
public class Salary{
// All the below are coming from lookup table like empLookUp, MonthLookup,
// YearLookup, CurrencyLookUp and they are joined using their primary key
private int empId;
private int month;
private int year;
private String currency;
// Issue here: previousMonthSalary actually needs to be populated when the
// Salary is loaded, but for previous month. How do I achieve this.
private Salary previousMonthSalary;
}
How to map the previousMonthSalary?
Most likely, you need to use the #JoinFormula annotation:
#ManyToOne(fetch = FetchType.LAZY)
#JoinFormula("(" +
"SELECT s.id " +
"FROM salary s " +
"WHERE s.empId = empId " +
"AND CASE WHEN month = 1 THEN s.year + 1 = year AND s.month = 12 ELSE s.year = year AND s.month - 1 = month END "
")")
private Salary previousMonthSalary;
Hope the use of lazy fetch in previousMonthSalary variable will resolve your issue.
#ManyToOne(fetch=fetchType.Lazy)
private Salary previousMonthSalary;

Update a column using hibernate

I have two classes Employee and Department.
public class Employee {
int empId;
String empName;
Boolean isEmpAvailable;
String empAddress;
Department department;
}
public class Department {
int deptId;
String deptName;
}
I have created hibernate files files for both classes Department.hbm.xml and Employee.hbm.xml
I like to update the column isEmpAvailable in the table Employee basing on a deptid in Department table.
Here I am facing problem with update query which I am not clear after reading in online documentation
public void updateEmployee(Employee emp, Department deptid){
String query= " update Employee set isEmpAvailable=? where deptid=?
Object[] values= {"true","133"};
getHibernateTemplate.update(query,values);
}
When i run the code the column doesn't get update. A error is thrown as
Entity not recognized: update Employee set isEmpAvailable=? where deptid=?
I have read online docs which have methods of getHibernateTemplate() which have return type as integer. Here I like to update the database directy by calling dao.updateEmployee without any returntype. I am unable do it. Please suggest me
Update in hibernate is done this way :
String hqlUpdate =
"update Employee e " +
"set e.isEmpAvailable = :isEmpAvailable " +
"where e.deptid = :deptid";
int updatedEntities = session.createQuery( hqlUpdate )
.setBoolean( "isEmpAvailable", isEmpAvailable )
.setInt( "deptid", deptid )
.executeUpdate();
OR
String jpqlUpdate =
"update Employee e " +
"set e.isEmpAvailable = :isEmpAvailable " +
"where e.deptid = :deptid";
int updatedEntities = entityManager.createQuery( jpqlUpdate )
.setBoolean( "isEmpAvailable", isEmpAvailable )
.setInt( "deptid", deptid )
.executeUpdate();
OR
String hqlVersionedUpdate =
"update versioned Employee e " +
"set e.isEmpAvailable = :isEmpAvailable " +
"where e.deptid = :deptid";
int updatedEntities = s.createQuery( hqlUpdate )
.setBoolean( "isEmpAvailable", isEmpAvailable )
.setInt( "deptid", deptid )
.executeUpdate();
If you want you can also use the saveOrUpdate() function. In this link there is an example and some documentation.

Categories