native query with spring data jpa doesn't return result - sql

Hello I have written the following method in spring data jpa repo:
#RestResource(exported = false)
#Query(
value = "select q.* " +
"from question q " +
"left join question_program qp " +
"on q.question_id = qp.question_id " +
"where " +
"q.difficulty_level_id = ?1 " +
"and " +
"q.paid = false " +
"and " +
"qp.program_id = ?2 " +
"order by random() " +
"limit ?3",
nativeQuery = true
)
List<Question> getFreeRandomQuestions(
#Param("df") Integer df,
#Param("programId") Integer programId,
#Param("qs") Integer qs);
It is returning an empty list whereas when I run the same query in pgadmin I get all the desired rows. It also works in spring data jpa if I remove the join with question_program. What am I doing wrong?
UPDATE:
I have tried select q ... and select * .... Both have the same problem
UPDATE:
I kind of solved this by implementing a service which fetches that data using sessionFactory and raw sql query!.

Related

How to write IN clause in hibernate native(createNative) query?

How to complete this query with IN clause?
ArrayList<Long> statusIds = new ArrayList<Long>();
_merchantTransaction.getMerchantTxnStatusList().forEach(statusItem ->{
statusIds.add(statusItem.getMerchantTxnStatusId());
});
Query query = entityManager.createNativeQuery("select *"
+ " from merchant_transactions mt"
+ " inner join appl_merchant_txn_statuses mts on mt.merchant_txn_status_id = mts.merchant_txn_status_id"
+ " where"
+ " mt.customer_id ="+ _merchantTransaction.getCustomerId()
+ " and mt.merchant_transaction_type_id = "+ _merchantTransaction.getMerchantTransactionType().getMerchantTransactionTypeId()
+ " and mt.merchant_txn_status_id in " + statusIds
,MerchantTransaction.class);
While executing, this result following query and it gives
SQLGrammerExecption.
select *
from merchant_transactions mt where
mt.customer_id = 3998
and mt.merchant_transaction_type_id = 2
and mt.merchant_txn_status_id in [1, 8]);
How to solve this?
Thanks & Regards,
Dasun.
You should consider using named parameter bindings instead of adding the parameters directly by concatenation as follows:
Query query =
entityManager.createNativeQuery("select *"
+ " from merchant_transactions mt"
+ " inner join appl_merchant_txn_statuses mts on mt.merchant_txn_status_id = mts.merchant_txn_status_id"
+ " where mt.customer_id = :customer_id"
+ " and mt.merchant_transaction_type_id = :merchant_transaction_type_id"
+ " and mt.merchant_txn_status_id in (:status_ids)", MerchantTransaction.class);
query.setParameter("customer_id", _merchantTransaction.getCustomerId());
query.setParameter("merchant_transaction_type_id", _merchantTransaction.getMerchantTransactionType().getMerchantTransactionTypeId());
query.setParameter("status_ids", statusIds);
Advantages of named parameter bindings as described in hibernate best-practices here:
you do not need to worry about SQL injection,
Hibernate maps your query parameters to the correct types and
Hibernate can do internal optimizations to provide better
performance.
As a side note, I see that you are using JPA's Entity Manager createNativeQuery, so this will work:
query.setParameter("status_ids", statusIds);
If you were using Hibernate createSQLQuery, you need this:
query.setParameterList("status_ids", statusIds);

Joining unrelated tables via JPQL

I have the following query which works. All the tables in this query have relations in some way.
#Repository(value = "ARepository")
public interface ARepository extends JpaRepository<CardEntity, String> {
#Query("SELECT xref.shortUtlTx FROM CardEntity card " +
"JOIN card.apexUrlCrossRef xref " +
"JOIN xref.sampleProdOffer offer " +
"WHERE xref.apexCard.cardNumber = :cardNum " +
"AND offer.apexeeOfferId = :myCode"
)
List<String> getAllValues(#Param("cardNum") String cardNum, #Param("myCode") String myCode);
}
But I also wish to join another table (Entity name -> UrlCountEntity) to this query but that table has no relation to the other tables in this query. Is there a way I could do this?
Based on reading a blog, I tried the following but throws errors.
Added this line to the query:
AND EXISTS (SELECT referCount FROM UrlCountEntity referCount WHERE
referCount.url.urlTx = xref.shortUtlTx)
#Repository(value = "ARepository")
public interface ARepository extends JpaRepository<CardEntity, String> {
#Query("SELECT xref.shortUtlTx FROM CardEntity card " +
"JOIN card.apexUrlCrossRef xref " +
"JOIN xref.sampleProdOffer offer " +
"WHERE xref.apexCard.cardNumber = :cardNum " +
"AND offer.apexeeOfferId = :myCode " +
"AND EXISTS (SELECT referCount FROM UrlCountEntity referCount WHERE referCount.url.urlTx = xref.shortUtlTx)"
)
List<String> getAllValues(#Param("cardNum") String cardNum, #Param("myCode") String myCode);
}
Error as follows:
Method threw
'org.springframework.dao.InvalidDataAccessResourceUsageException'
exception.
could not extract ResultSet; SQL [n/a]
Based on this article:
Using Hibernate 5.1 or newer you can join two unrelated tables via JQPL same way you would do it in SQL:
SELECT first
FROM First first JOIN
Second second ON first.property = second.property
WHERE first.property = :param
So you would need to change your query to something like this:
#Query("SELECT xref.shortUtlTx FROM CardEntity card " +
"JOIN card.apexUrlCrossRef xref " +
"JOIN xref.sampleProdOffer offer " +
"JOIN UrlCountEntity referCount ON referCount.url.urlTx = xref.shortUtlTx" +
"WHERE xref.apexCard.cardNumber = :cardNum " +
"AND offer.apexeeOfferId = :myCode")
List<String> getAllValues(#Param("cardNum") String cardNum, #Param("myCode") String myCode);

Running HQL query in console

I am trying to run the following query in IntelliJ:
#Query(value = "" +
"SELECT offer FROM OfferEntity offer " +
" JOIN offer.placeOwnership AS owner " +
" JOIN owner.place AS place " +
"WHERE " +
" place.id = :placeId AND " +
" offer.dayFrom = :offerDate AND " +
" offer.repeating = false")
as I am doing so, I get ask to provide the parameters placeId and offerDate. My problem is I have no idea about the latter.
I have no idea how I can run this query.
I also tried to run it manually inside the console like this:
SELECT offer FROM OfferEntity offer
JOIN offer.placeOwnership AS owner
JOIN owner.place AS place
WHERE
place.id = 1L AND
offer.dayFrom = java.time.LocalDate.parse("2018-10-08") AND
offer.repeating = false
but that gives my a syntax error.

#query with named #param returning empty result set when using sql IN

Btw this is already working with a jdbc template based solution that I wrote. It's not me wanting to do the rewrite, it is the tec lead's idea. It is giving me a headache.
Lets not get into the discussion on why this is or isn't a good idea, but rather how to make it work.
in my repo
#Repository
interface Foo...extends JpaRepository
this works:
#Query(value = "SELECT t.td, em.ct, j.dsc AS bs, ct.dsc AS ct_name, "
+ "t.tn, et.dsc, f.f_id, f.f_life, f.fl_name, em.f_note "
+ "FROM ext_master em join tax t on em.td = t.td "
+ "join bs j on j.bs = t.bs "
+ "join ex_type et on em.ex_type = et.ex_type "
+ "join ct ct on ct.ct = em.ct "
+ "left join ex_f ef on em.td = ef.td and em.ct = ef.ct "
+ "left join f f on ef.f_id = f.f_id "
+ "WHERE em.ct in ( 'CC' ) "
+ "AND t.state IN ('FF','AK','AL','GA')"
+ "ORDER BY bs, t.tn", nativeQuery = true)
List<Object> getExtensionsByCustTypeAndState(#Param("custTypes") String custTypes, #Param("states") String states);
this doesn't returns empty result set
#Query(value = "SELECT t.td, em.ct, j.dsc AS bs, ct.dsc AS ct_name, "
+ "t.tn, et.dsc, f.f_id, f.f_life, f.fl_name, em.f_note "
+ "FROM extension_master em join tax t on em.td = t.td "
+ "join bs j on j.bs = t.bs "
+ "join exemption_type et on em.ex_type = et.ex_type "
+ "join ct ct on ct.ct = em.ct "
+ "left join ex_f ef on em.td = ef.td and em.ct = ef.ct "
+ "left join f f on ef.f_id = f.f_id "
+ "WHERE em.ct in ( :custTypes ) "
+ "AND t.state IN ('FF', :states)"
+ "ORDER BY bs, t.tn", nativeQuery = true)
List<Object> getExByCustTypeAndState(#Param("custTypes") String custTypes, #Param("states") String states);
both can have one or multiple values, I tried:
with both params like {:states} :#{#states}
with the value inside the param
surrounded by " or by '
passing the whole line in the parameter like "AND t.state IN ('FF','AK','AL','GA')"
passing the 'FF','AK','AL','GA' in the states param and subtituting the in the query with
+ "AND t.state IN ( :states)"
I did write a simple query to make sure I am getting the parameters passed in right. so that's working.
Can anyone write this right, so that the in statements work, or tell me why it is not possible.
Thank you.
You pass all the possible values in one parameter that's why you don't get the results you are expecting.
You have to change the where clause like this:
"WHERE em.ct in ( :custTypes1, :custTypes2, :custTypes3 .... :custTypesN) "
this ended up being the simplest solution
instead of :
"WHERE em.ct in ( :custTypes ) "
+ "AND t.state IN ('FF', :states)"
do:
"WHERE em.ct in :custTypes "
+ "AND t.state IN :states "
and add the FF to the states string on before I call the function.

Casting error after jpa query on database

This query gives a array ob objects instead of giving me the Tracking object back.
In the log i see:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.quoka.qis.ads.web.tracking.Tracking
#NamedNativeQuery(
name = "Tracking.findByNo",
query = "select * " +
"from inet.TRACKING t " +
"where t.prditmNO = ?1"
)
TypedQuery<Tracking> q = em.createNamedQuery("Tracking.findByNo", Tracking.class);
q.setParameter(1, adno);
List<Tracking> list = q.getResultList();
return list.isEmpty()?null:list.get(0);
Thanks for you help.
You use a native query. You should use a JPA query.
#NamedQuery( name = "Tracking.findByNo",
query = "select t " +
"from Tracking t " +
"where t.prditmNO = ?1" )