How to get incremental value in JPA? - java

I'm trying to get incremented value only while extracting data from Table. Below is my code snippet.
public interface Repo extends PagingAndSortingRepository<T,T> {
#Query("Select new CustomObject(name, phone, place) from table")
List<CustomObjectDTO> getData();
}
Note: CustomObjectDTO has all three attributes mentioned in select query.
May I know please How can I get the incrementalID as first col in select query ? I mean need a serial number with every record in select query output.
Any suggestions ?

It seems to be this:
#Query("Select new CustomObject(incremantal_column_name,name, phone, place) from table")
List<CustomObjectDTO> getData();
and in CustomObjectDTO class:
#Column(name = "incremantal_column_name)
long incrementalID;

Related

Parameters not being set in native query

I am working on a SpringBoot Application and I am trying to do a simple delete using: #Query(value="", nativeQuery = true)
My query has dynamic parameters but the parameters are not getting substituted and I am also not getting any error on console.
I tried the NativeQuery with hardcoded parameters and it worked perfectly fine.
Below is the code:
#Repository
public interface TypGbPccRepo extends JpaRepository<TypGbPcc, String>{
#Transactional
#Modifying(ClearAutomatically = true)
#Query(value = "delete from T_ST_KFR__TYP_GB_PCC typ where Trunc(typ.GUELTIG_AB) IN (?1) and typ.GB_PCC IN (?2)" , nativeQuery=true)
void deleteRecords(String datumStr , String gbPccStr);
}
I even tried the below query:
#Query(value = "delete from T_ST_KFR__TYP_GB_PCC typ where Trunc(typ.GUELTIG_AB) IN (:datumStr ) and typ.GB_PCC IN (:gbPccStr)" , nativeQuery=true)
void deleteRecords(#Param("datumStr ") String datumStr , #Param("gbPccStr") String gbPccStr);
Parameters I am trying to substitute:
datumStr - TO_DATE('12-Sep-2012', 'dd-MM-yy'), TO_DATE('14-Sep-2012', 'dd-MM-yy')
gbPccStr - 'P0','P1'
I am implementing the above code to delete records based on a Composite Primary key which is a combination of GUELTIG_AB & GB_PCC. If possible suggest me how to achieve this with a query QueryMethod?
I have been able to delete records based on Primary which is not composite by using QueryMethod but I am unable to do this for a composite Primary key. I have to delete Multiple records in one go.
Below is my POJO
#Entity
#IdClass(TypGbPccId.class)
#Table(name="T_ST_KFR_TYP_GB_PCC")
public class TypGbPcc implements Serializable{
private static final long serialVersionUID = .....
#Id
#Column(name="GB_PCC")
private String gbPcc = null ;
#Column(name="GB_PCC_desc")
priavte String gbPccDesc = null ;
#Column(name="GB_PCC_SQL")
priavte String gbPccSql = null ;
#Id
#Column(name="GUELTIG_AB")
#JsonFormat(pattern = "dd-MM-yyyy")
private String gueltigAb = null ;
}
setter & getters here
These are bind parameters, they get passed to the database separately from the SQL statement. They are not used to create a new SQL statement with the parameters concatenated into it.
So what your Trunc(typ.GUELTIG_AB) IN (?1) with the given parameter really boils down to is:
Throw away the time part from GUELTIG_AB, convert it to a String using the systems default format, whatever that happens to be and check if the resulting string is contained in the list consisting of a single string: "TO_DATE('12-Sep-2012' , 'dd-MM-yy'),TO_DATE('14-Sep-2012' , 'dd-MM-yy')"
What you probably want is closer to:
Is GUELTIG_AB element in the list of dates with the two elements 12th of September 2014 and 14th of September 2014
Therefore your method should look like:
#Modifying(ClearAutomatically = true)
#Query(value = "delete from T_ST_KFR__TYP_GB_PCC typ " +
"where Trunc(typ.GUELTIG_AB) IN (?1) " +
"and typ.GB_PCC IN (?2)"
, nativeQuery=true)
void deleteRecords(List<java.sql.Date> dates , List<String> gbPccStr);
Note: you don't need the #Transactional annotation on the method, nor the #Repository annotation on the interface.
I am implementing the above code to delete records based on a Composite Primary key which is a combination of GUELTIG_AB & GB_PCC. If possible suggest me how to achieve this with a query QueryMethod?
That is not at all what the current query is doing.
If you have rows with the following keys:
(d1,p1)
(d1,p2)
(d2,p1)
(d2,p2)
You can't delete for example (d1,p1) and (d2,p2) with this approach, because it will also delete the other two elements.
In order to fix that declare an #IdClass on your entity. Specify that in the type parameters for your Repository and use a normal query method.
First of all there is a space after datumStr in #Param("datumStr "). Next, change its type to List of String and pass the date strings in your default DB date format.
(You should change the type of gbPccStr to List of Sting as well)
You can do something like this.
#Query(value = "delete from TypGbPcc where func('TRUNC',gueltigAb) IN func('TO_DATE',:dateOne,'dd/mm/yyyy') and
func('TRUNC',gueltigAb) IN func('TO_DATE',:dateTwo,'dd/mm/yyyy') and gbPcc IN (:gbPccStr)" , nativeQuery=true)
void deleteRecords(#Param("dateOne") String dateOne ,#Param("dateTwo") String dateTwo, #Param("gbPccStr") String gbPccStr);
in dateOne give first date in dateTwo give second date

How to work with SQL Views in Spring JPA?

I'm currently working on a project with Spring and HANA DB.
I have already an Webservice which is working properly, but I need to select a View from my HANA DB(created outside of the Spring Webservice).
My view is made from 2 tables, 4 of its fields are SUM of one column from one of the tables(which counts how much of each of each 4 possible values and shows that as a number in each of the 4 fields).
I read about in some Spring JPA posts that it should work properly with a simple select, my questions are:
I usually make selects like this:
TypedQuery<name_of_the_model_class> query = em.createQuery("SELECT c FROM NameOfTheTable ORDER BY c.some_field DESC WHERE c.name =?1 ", name_of_the_model_class.class);
query.setParameter(1, name_to_search);
And then after that I just return the list to the Controller and the Controller shows that in a JSON.
The problem is, I have created this View in Eclipse, using directly SQL code in HANA DB, without creating it at the Webservice.
I would like to know, is there a way to select like I showed above, returning it without a model class? It would just need a class with exactly the same fields like a model class but without #Entity annotation on it?
OR is there a way to create a view like a model class in Spring JPA? If there is a way, what are the annotations to make it work?
Spring JPA would not accept me to return it without a class would it?
I read plenty posts but didn't found it, even in the Manual it doesn't give clear specification or examples.
Thanks a lot for your time, if I didn't explained it well pls tell me, I'm really stuck on this.
More info(my latest try):
My entire search function at the DAO:
public List<IncidentStatusResultsUser> getIncidentStatusByUser(String userID) throws ParseException {
List<IncidentStatusResultsUser> resultList = em.createQuery("SELECT c FROM USERSTATUS ORDER BY c.uploadDateTime DESC WHERE c.userID=?1 ").setMaxResults(48).getResultList();
Collections.reverse(resultList);
return resultList;
}
I have created a class to just receive the data with the same fields of the view:
public class IncidentStatusResultsUser {
private Date uploadDateTime ;
private int status1;
private int status2;
private int status3;
private int status4;
//All gets and sets ommited
public IncidentStatusResultsUser (Date uploadDateTime, long status1, long status2, long status3, long status4) {
this.uploadDateTime = uploadDateTime;
this.status1= status1;
this.status2= status2;
this.status3= status3;
this.status4= status4;
}
}
EDIT-2: Added public constructor inside the class.
Best Regards,
Famibica
You should be able to map your view to a JPA object as long as it has a primary key (or composite key). You can then map to a Spring JPA Reposiry so your query would go from -
TypedQuery<name_of_the_model_class> query = em.createQuery("SELECT c FROM NameOfTheTable ORDER BY c.some_field DESC WHERE c.name =?1 ", name_of_the_model_class.class);
query.setParameter(1, name_to_search);
To
findBySomeFieldOrderBySomeFieldDesc(String name_to_search)
If you want JPA returning a list of object directly, you need a DTO just like the IncidentStatusResultsUser you created. make sure you have a constructor taking all fields, something like:
public IncidentStatusResultsUser(Date uploadDateTime, int status1, int status2, int status3, int status4)
Then in your query String dtoQuery, you can do:
SELECT new IncidentStatusResultsUser(c.uploadDateTime, c.status1,c.status2,c.status3,c.status4)
FROM NameOfTheTable
ORDER BY c.some_field DESC
WHERE c.name =?1
Then you should be able to call your stuff:
List<IncidentStatusResultsUser> resultList = em.createQuery(dtoQuery).setMaxResults(48).getResultList();
Hope it works for you:)

Spring data JPA query behaves unexpectedly

I have these entities:
public class Order_status_sas {
private Order_sas order;
private Date lastModified;
...
}
public class Order_sas {
private long id;
...
}
My CrudRepository:
public interface StatusesWareHouseRepository extends CrudRepository<Order_status_sas, Long> {
Order_status_sas findFirstByOrderIdOrderByLastModifiedDesc(long id);
}
I expect that method findFirstByOrderIdOrderByLastModifiedDesc would return first row from table Order_status_sas, where order.id = <some_id> sorted by field lastModified, but in log I see this query:
Hibernate: select ...
from order_status_sas a
left outer join orders_sas b
on a.order_id=b.id
where b.id=?
order by a.last_modified desc
This query does not return me one row, but returns a list of rows. It seems that Spring Data do not look at word First in my method name. Also, I get an Exception:
org.springframework.dao.IncorrectResultSizeDataAccessException:
result returns more than one elements; nested exception is javax.persistence.NonUniqueResultException: result returns more than one elements
Please, tell me what I am doing wrong and how can I achieve my purpose?
EDITED:
I edited my StatusesWareHouseRepository with custom query:
#Query("select s from Order_status_sas s where s.order.id = ?1 order by s.lastModified desc limit 1")
Order_status_sas findFirstByOrderIdOrderByLastModifiedDesc(long id);
but the query, executed by Hibernate, haven't changed. It looks like this:
select ...
from order_status_sas s
where s.order_id=?
order by s.last_modified desc
OK, I understood #PriduNeemre point. Lets leave the DB model and come back to the JPA question. Here is another example:
#Entity
public class Client {
....
}
public interface ClientRepository extends CrudRepository<Client, Integer> {
Client findFirstByOrderByNameDesc();
}
Hibernate query still looks like this:
select ...
from clients c
order by c.name desc
Have you tried adding a #Query annotation (see here) on top of your findFirstByOrderIdOrderByLastModifiedDesc(..) method to specify the expected behaviour by hand? A (non-related) example on how this could work:
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
#Query("SELECT I FROM Invoice I JOIN I.customer C JOIN C.user U WHERE
U.username = :username")
public List<Invoice> findInvoicesByUsername(#Param("username")
String username);
}
Note that the query language used in the annotation body is in fact JPQL, not SQL. For more examples on the #Query annotation, see the Spring Data docs here.
PS: I'm also having conflicted feelings about your domain object structure, i.e. whether an instance of Order_sas should really be stored in an instance of Order_status_sas - shouldn't it be the other way around? Normally you would want to store the reference objects in your main domain object, not vice versa. (There's a slight possibility that I'm just not getting it right, though.)
EDIT: I would even go as far as to say that considering your current domain model, Hibernate is doing everything right except missing a LIMIT 1 clause to limit the expected resultset to one single row. The query itself is extremely inefficient, though, and could be improved by fixing your skewed domain model.

List items per sales using JPA

I have two entities :
Items(id, user_id, title, price);
Purchases(id, item_id, user_id, date);
Using JPA, I'd like to list all the items that have been purchased more than X times, ordered by their purchased times (the first being the most purchased).
I managed to have the correct SQL request, but how can I do that in JPA (possibly without using createQuery or something equivalent) :
SELECT i.title, COUNT(p.id) as rank FROM items AS i LEFT OUTER JOIN purchases AS p ON p.item_id = i.id WHERE rank > X GROUP BY i.title ORDER BY rank DESC;
// of course, X is an int!
Thank you for your help! :)
Update:
I indicated to avoid createQuery but I didn't explained why.
The thing is, I made a class dedicated to generating the query, it looks like :
public class Arguments {
protected HashSet allowedOrders = new HashSet();
protected Collection args = new ArrayList();
// constructor and some other methods
// this one works great
public void setPriceMin(int price) {
query += " AND price > ?";
args.put(price);
}
// sames method for setPrice (= ?), and setPriceMax (= <)
// this one doesn't :/
public void setSalesMin(int sales) {
// here's my problem
}
}
But It's (really) possible that my methods isn't good. And since you bring up the Criteria, maybe I should take a look at it, even for "setPriceMin" and all the other methods.
How'd you do?
You can't do it without a Query.
Either rewrite the Query as JPQL (very similar, but you will have to replace ids with objects and do joins on properties, not on tables), or use the JPA 2 CriteriaQuery API. (Or use your SQL as a native Query, but this is usually a bad idea)

Solving JPA query finding the last entry in connected list

Following class structure is given:
class Job
{
String description;
Collection<JobHistory> history;
}
class JobHistory
{
Date assignDate;
User jobOwner;
}
class JobOwner
{
String name;
String id;
}
This class-structure is accessible on the db via JPA. In the DAO-Layer I can write queries in JPA syntax.
The Problem: I want a list with Job and JobHistory entries for a given owner with given id and who is the last one in the Jobhistory of the job (ordered by assignDate). Sounds quite complicated, perhaps simpler: give me all jobs and JobHistory where specified owner is the actual owner of the job.
Update: for clarity I will slightly change the names of the classes.
class Job
{
String description;
Collection<JobOwnerHistory> history;
}
class JobOwnerHistory
{
Date assignDate;
User jobOwner;
}
class JobOwner
{
String name;
String id;
}
Every Job has a history of his owners sorted by assignDate. The actual owner got the job last assigned (i.e. MAX(assignDate)). I want find for every job the JobOwnerHistory entry with MAX(assignDate) for a specific user User.
I found the following answer for the query:
SELECT j, h FROM Job j JOIN j.history h JOIN h.jobOwner u
WHERE u.name = :name AND
(SELECT MAX(h2.assignDate) FROM Job j2 JOIN j2.history h2
WHERE h2 member of j.history) = h.assignDate
The most important part in the query is the subselect with MAX(h2.assignDate) because I want to get the job and the newest entry in the owner-history.
Try:
SELECT j, j.history FROM Job j JOIN User u WHERE u.name = :name
If I were to do this in EclipseLink, I would change it slightly:
public List<Job> getAllJobsForUser(String username) {
List<Job> jobs = entityManager
.createQuery("SELECT j FROM Job j JOIN User u WHERE u.name = :name")
.setParameter("name", username)
.setHint(QueryHints.BATCH, "j.history")
.queryForList();
}
The difference? In the first version, you're returning two objects, so you have to retrieve them from a List or Object arrays whereas in the second, the query hint just loads all the job histories from an (assumedly) lazyy one-to-many relationship.
I don't know if Hibernate has an equivalent to this. Toplink Essentials doesn't. But it's one of my favourite features of EclipseLink.
Oh and obviously you can (and probably should) use a named query instead of an adhoc query like I've done (since those can be verified during the build).

Categories

Resources