JPA nativeQuery taking a list/set/array as parameter - java

Using a postgres database, I have the following entity : table cards.combo and column colors VARCHAR[], example of values {'red', 'blue'}
I want to find the Combos that have no colors in common, using the overlap operator (&&)
I can't find out how to formulate the correct nativeQuery, something similar to this :
#Query(nativeQuery = true, value = "SELECT * FROM cards.combo cc WHERE cc.colors && CAST(ARRAY[(:providedColors)] AS VARCHAR[])")
List<Combo> findOverlaps(#Param("providedColors") List<String> providedColors);
In a console, this test works fine :
SELECT * FROM cards.combo cc WHERE cc.colors && CAST(ARRAY['red'] AS VARCHAR[])
The syntax (:param) is supposedly correct with other primitive parameters (int, string). I struggle to get the param providedColors converted to an array[] in the query.
Thanks !
edit : found a workaround :provide colors as a csv string, and use && CAST(STRING_TO_ARRAY((:providedColors),',') AS VARCHAR[])

public interface EmployeeDAO extends JpaRepository<Employee,Integer> {
List<Employee> findByEmployeeNameIn(List<String> names);
// 1. Spring JPA In cause using method name
#Query("SELECT e FROM Employee e WHERE e.employeeName IN (:names)")
// 2. Spring JPA In cause using #Query
List<Employee> findByEmployeeNames(#Param("names")List<String> names);
#Query(nativeQuery =true,value = "SELECT * FROM Employee as e WHERE e.employeeName IN (:names)") // 3. Spring JPA In cause using native query
List<Employee> findByEmployeeName(#Param("names") List<String> names);
}

Related

Spring data JPA nativeQuery order by is invalid

The Spring Data Jpa Method like this:
#Query("select pb.id,pp.max_borrow_amt,pp.min_borrow_amt
from product_loan_basic pb left join product_loan_price pp on pb.code=pp.product_code
where pb.code IN(?1) and pb.status='publish' order by ?2 ",
nativeQuery = true)
List<Object[]> findByCodesIn(List<String> codes,String orderby);
then order by is " max_borrow_amt desc ", but this is invalid.
the List is disordered.
Dynamic sorting in Spring Data JPA
If you used a JPA query you could use Sort as an argument of your query method to define the sorting order:
#Query("select m from Model m")
List<Model> getSortedList(Sort sort);
and then, for example:
List<Model> models = getSortedList(Sort.by(Sort.Direction.DESC, "name"));
But Spring Data JPA can't use Sort with native queries:
Spring Data JPA does not currently support dynamic sorting for native queries, because it would have to manipulate the actual query declared, which it cannot do reliably for native SQL.
However you can use Pageable and its implementation PageRequest instead:
#Query(value = "select m.name as name from models m", nativeQuery = true)
List<ModelProjection> getSortedList(Pageable p);
and then:
List<ModelProjection> modelNames = getSortedList(PageRequest.of(0, 1000, Sort.Direction.DESC, "name"));
P.S. Instead of array of Objects as returned parameters, it's better to use projections, for example:
public interface ModelProjection {
String getName();
}
Note that in this case the good practice is to use aliases in queries (ie m.name as name). They must match with correspondent getters in the projection.
Working demo and test.
Thanks everyone!
My problem has been solved.
If you want to use Spring data jpa nativeQuery & Sort, you should do like this:
#Query(
value ="select pb.id,pp.max_borrow_amt from product_loan_basic pb left join product_loan_price pp on pb.code=pp.product_code ORDER BY ?#{#pageable} ",
countQuery = "select count(*) from product_loan_basic",
nativeQuery = true
)
Page<Object[]> findAllProductsAndOrderByAndSort(Pageable pageable);
?#{#pageable} is required and countQuery is required.
Pageable pageable = new PageRequest(0,1000,Sort.Direction.DESC,"id");
then the result is sorted.
See Spring Data and Native Query with pagination.

Hibernate result list cast to get rows

Hello I had problem with iterate Hibernate ResultList
I had followed query that I got from external class:
queryContent = "select distinct c.identity, c.number, c.status, ctr.name, aab.paymentConditions.currency from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
And I must sum whole aab.paymentConditions.currency, check numbers of statutes and names.
I want to do this by iterate list of results:
Query q = session.createQuery(queryContent);
List result = q.list();
Long wholeCurrency, numberOfStatutes;
for(Object res : result){
//wholeCurrency += res.getColumnName?
}
My question is how to cast res Object to have possibility to get concrete column values? I had read about create map inside hibernate query but I don't know it is good practice to modyfied query string by adding
"new map(" prefix and then ")"
before from sql statement
Solution:
After All I decided to use map in my query. I modified my external query by adding hibernate map statement by replacing select by 'select new map(' and from by ') from'.
Additional thing is to add 'as' statement with name of key because without them column keys are integer.
So after all my query looks like follow:
"select new map( distinct c.identity, c.number, c.status as status, ctr.name as name, aab.paymentConditions.currency as currency ) from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
That was the most siutable solution for me, I tried with 'NEW com.example.MyClass' as Kostja suggested but in my case I didn't have control for incoming query so I can not rely on pernament constructor.
new List( select...
Is also interest but it also didn't tell me on with position I have my field that give me information.
If I understand correctly, you want to have a typed representation of your result without it being an entity itself. For this, you can use constructor queries:
"SELECT NEW com.example.MyClass( e.name, e.data) FROM Entity e"
MyClass has to have a matching constructor. Full qualification (com.example) is not mandatory AFAIK.
If you are using this query often, creating a view in the DB may be a good idea. You can map a view to an entity just as if it were a regular table, but please note that you cannot store changes to you data over a mapped view.
EDIT: Turns out, mapping to an unspecified Map is alright with Hibernate:
select new map( mother as mother, offspr as offspr, mate as mate )
As per http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-select-clause
you can use
queryContent = "select new list(distinct c.identity, c.number, c.status, ctr.name, aab.paymentConditions.currency) from AgreementStateBean ast join ast.currentAgreement aab join conagr.contract c where c.agreementStateId = ? and con.mainContractor = true ? "
And you get List<List> as result.

Get distinct values via hibernate

I want to get distinct values by a parameter:
#Transactional
public List<data> getAllFromColumn(String identifier) {
List<data> resultList = em.createQuery("SELECT DISTINCT p.market FROM data p", Data.class).getResultList();
return resultList;
}
My problem is that this only returns me a NullPointerException. Any recommendations what is wrong, or what I can do differently?
I appreciate your answer!
If HQL doesn't support select distinct (which it doesn't seem to according to the syntax), you can do this using group by:
SELECT p.market
FROM data p
GROUP BY p.market;

Map fetch/result from jooq to specific Record

When I currently query with Jooq I am explicitly casting each record-object to the expected record-type.
Result<Record> result = sql.select().from(Tables.COUNTRY).fetch();
for (Record r : result) {
CountryRecord countryRecord = (CountryRecord) r;
//Extract data from countryRecord
countryRecord.getId();
}
Is it, with Jooq, possibly to cast the result straight into the desired record-type?
Such as (this does not compile):
Result<CountryRecord> countryRecords = (Result<CountryRecord>) sql.select().from(Tables.COUNTRY).fetch();
for (CountryRecord cr : countryRecords) {
cr.getNamet();
//etc...
}
#Lukas,
Actually we are using fetchInto() to convert the results to list of object.
For example:
Employee pojo matching database table is employee.
List<Employee> employeeList = sql.select(Tables.Employee)
.from(Tables.EMPLOYEE).fetchInto(Employee.class);
similarly, how could we convert the records we are fetching using joins?
For example:
Customer pojo matching database table is customer.
Employee pojo matching database table is employee.
sql.select(<<IWantAllFields>>).from(Tables.CUSTOMER)
.join(Tables.EMPLOYEE)
.on(Tables.EMPLOYEE.ID.equal(Tables.CUSTOMER.EMPLOYEE_ID))
.fetchInto(?);
You shouldn't be using the select().from(...) syntax when you want to fetch generated record types. Use selectFrom() instead. This is documented here:
http://www.jooq.org/doc/3.1/manual/sql-execution/fetching/record-vs-tablerecord
So your query should be:
Result<CountryRecord> countryRecords = sql.selectFrom(Tables.COUNTRY).fetch();
for (CountryRecord cr : countryRecords) {
cr.getNamet();
//etc...
}

How to run an aggregate function like SUM on two columns in JPA and display their results?

I am new to JPA. So my question should be so simple to some.
Below is the Simple Query in SQL which i would like to convert to JPA. I already have an entity class called TimeEnt.
SELECT
SUM(TimeEntryActualHours) as UnBilledHrs,
SUM (TimeEntryAmount) as UnbilledAmount
FROM TimeEnt WHERE MatterID = 200
The JPA Query Language does support aggregates functions in the SELECT clause like AVG, COUNT, MAX, MIN, SUM and does support multiple select_expressions in the SELECT clause, in which case the result is a List of Object array (Object[]). From the JPA specification:
4.8.1 Result Type of the SELECT Clause
...
The result type of the SELECT
clause is defined by the the result
types of the select_expressions
contained in it. When multiple
select_expressions are used in the
SELECT clause, the result of the query
is of type Object[], and the
elements in this result correspond in
order to the order of their
specification in the SELECT clause
and in type to the result types of
each of the select_expressions.
In other words, the kind of query you mentioned in a comment (and since you didn't provide your entity, I'll base my answer on your example) is supported, no problem. Here is a code sample:
String qlString = "SELECT AVG(x.price), SUM(x.stocks) FROM Magazine x WHERE ...";
Query q = em.createQuery(qlString);
Object[] results = (Object[]) q.getSingleResult();
for (Object object : results) {
System.out.println(object);
}
References
JPA 1.0 Specification
4.8.1 Result Type of the SELECT Clause
4.8.4 Aggregate Functions in the SELECT Clause
Lets think we have entity called Product:
final Query sumQuery = entityManager
.createQuery("SELECT SUM(p.price), SUM(p.sale) FROM Product p WHERE p.item=:ITEM AND ....");
sumQuery.setParameter("ITEM","t1");
final Object result= sumQuery.getSingleResult(); // Return an array Object with 2 elements, 1st is sum(price) and 2nd is sum(sale).
//If you have multiple rows;
final Query sumQuery = entityManager
.createQuery("SELECT SUM(p.price), SUM(p.sale) FROM Product p WHERE p.item in (" + itemlist
+ ") AND ....");
// Return a list of arrays, where each array correspond to 1 item (row) in resultset.
final List<IEniqDBEntity> sumEntityList = sumQuery.getResultList();
Take a look at the EJB Query Language specification.
The idiom is very similiar to standard SQL
EntityManager em = ...
Query q = em.createQuery ("SELECT AVG(x.price) FROM Magazine x");
Number result = (Number) q.getSingleResult ();
Regards,

Categories

Resources