I'm trying to have limits with nativeQuery = true but Spring JPA can't find the query for this.
My error is:
Caused by: java.lang.IllegalStateException: Using named parameters for method public abstract void se.danielmartensson.repositories.DataRepository.deleteByJobNameOrderByDateTimeLimit(java.lang.String,long,long) but parameter 'Optional[jobName]' not found in annotated query 'DELETE FROM Data data ORDER BY data.dateTime WHERE data.jobName =: jobName LIMIT firstIndex = :firstIndex, selectedSamples = :selectedSamples'!
So I'm guessing that LIMIT should have different attributes, rather than firstIndex and selectedSamples ? What can it be then?
Where is my query from my Repository in Spring Boot
#Query(value = "SELECT * FROM Data data ORDER BY data.dateTime WHERE data.jobName = :jobName LIMIT firstIndex = :firstIndex, selectedSamples = :selectedSamples", nativeQuery = true)
List<Data> findByJobNameOrderByDateTimeLimit(#Param("jobName") String jobName, #Param("firstIndex") long firstIndex, #Param("selectedSamples") long selectedSamples);
#Modifying
#Query(value = "DELETE FROM Data data ORDER BY data.dateTime WHERE data.jobName =: jobName LIMIT firstIndex = :firstIndex, selectedSamples = :selectedSamples", nativeQuery = true)
void deleteByJobNameOrderByDateTimeLimit(#Param("jobName") String jobName, #Param("firstIndex") long firstIndex, #Param("selectedSamples") long selectedSamples);
I have created a sample project that uses H2. You must change limit and offset part in which database you are using. For the delete operation, there is delete from table where id in (select id from table where .. order by .. limit .. offset ..) is defined.
Note: Lombok is used for getter, setter and toString. It is not required.
DataRepository.java
public interface DataRepository extends JpaRepository<Data, Integer> {
#Query(value = "SELECT * FROM Data data WHERE data.jobName = :jobName ORDER BY data.dateTime limit :selectedSamples offset :firstIndex"
, nativeQuery = true)
List<Data>findByJobNameOrderByDateTimeLimit(#Param("jobName") String jobName, #Param("firstIndex") Integer firstIndex, #Param("selectedSamples") Integer selectedSamples);
#Transactional
#Modifying
#Query(value = "DELETE FROM Data data WHERE data.id in (select id from Data d where d.jobName = :jobName order by d.dateTime limit :selectedSamples offset :firstIndex)"
, nativeQuery = true)
void deleteByJobNameOrderByDateTime(#Param("jobName") String jobName, #Param("firstIndex") Integer firstIndex, #Param("selectedSamples") Integer selectedSamples);
}
Data.java
#lombok.Data
#Entity
#Table
public class Data {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "jobName")
private String jobName;
#Column(name = "dateTime")
private LocalDateTime dateTime;
public Data() {
}
public Data(String jobName, LocalDateTime dateTime) {
this.jobName = jobName;
this.dateTime = dateTime;
}
}
Test
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.List;
#SpringBootTest
class DemoApplicationTests {
#Autowired
private DataRepository dataRepository;
#Test
void test1() {
// insert dummy records
dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(1)));
dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(2)));
dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(3)));
dataRepository.save(new Data("job1", LocalDateTime.now().minusMinutes(4)));
// get records
List<Data> dataList = dataRepository.findByJobNameOrderByDateTimeLimit("job1", 0, 4);
for (Data data : dataList) {
System.out.println(data);
}
// delete
dataRepository.deleteByJobNameOrderByDateTime("job1", 1, 2);
// get records
dataList = dataRepository.findByJobNameOrderByDateTimeLimit("job1", 0, 4);
for (Data data : dataList) {
System.out.println(data);
}
}
}
Output
Hibernate: SELECT * FROM Data data WHERE data.jobName = ? ORDER BY data.dateTime limit ? offset ?
Data(id=4, jobName=job1, dateTime=2021-01-08T05:25:31.830)
Data(id=3, jobName=job1, dateTime=2021-01-08T05:26:31.829)
Data(id=2, jobName=job1, dateTime=2021-01-08T05:27:31.827)
Data(id=1, jobName=job1, dateTime=2021-01-08T05:28:31.756)
Hibernate: DELETE FROM Data data WHERE data.id in (select id from Data d where d.jobName = ? order by d.dateTime limit ? offset ?)
Hibernate: SELECT * FROM Data data WHERE data.jobName = ? ORDER BY data.dateTime limit ? offset ?
Data(id=4, jobName=job1, dateTime=2021-01-08T05:25:31.830)
Data(id=1, jobName=job1, dateTime=2021-01-08T05:28:31.756)
Mysql
For mysql delete operation is successful with below script.
Reference: MySQL DELETE FROM with subquery as condition - Answer
#Transactional
#Modifying
#Query(value = "DELETE FROM Data WHERE id in (select id from (select id from Data where jobName = :jobName order by dateTime limit :selectedSamples offset :firstIndex) x)"
, nativeQuery = true)
void deleteByJobNameOrderByDateTime(#Param("jobName") String jobName, #Param("firstIndex") Integer firstIndex, #Param("selectedSamples") Integer selectedSamples);
If you just want to get the row which jobName and firstIndex and selectedSamples match the parameters. you should use correct SQL syntax and put them in where.
SELECT * FROM Data data
WHERE data.jobName = :jobName AND firstIndex = :firstIndex AND selectedSamples = :selectedSamples
ORDER BY data.dateTime
the correct syntax is like this :
select *
from [table]
where 'condiction'
order by [column]
limit [int]
LIMIT however is used to set the max tuples SQL return, for example if the query return 10K rows but you only want to look at first 5 rows, you can use limit 5 to tell SQL only return first 5 fetch.
Also in different DBMS there might need to use different syntax or method to achieve the same thing, like in ORACLE we got no limit clause, instead we got FETCH or simply using ROWNUM.
Related
I have searched all over stackoverflow.com but I have not found this discussion.
I know my problem, I was just wondering if JPA can handle this in any way without a lot of work...
What I have is an #Entity that I want to use with multiple SQL-Native-Queries.
#Entity
public class TestEntity {
#Id
private String ID;
private String ID1;
private String ID2;
private String ID3;
}
Names in the database are equal to Field names.
I then have two selects:
SELECT ID1, ID2 from DATABASE;
SELECT ID2 from DATABASE;
And two native queries for those selects:
#Query(value = "SELECT ID2 from DATABASE", nativeQuery = true)
List<TestEntity> testNativeQuery ();
And the Error I get:
[ERROR] 2021-11-30 10:37:20 [main] [SqlExceptionHelper] The column name ID1 is not valid.
How could I tell JPA that if it does not find the Column name that it should just replace it will
null
?
Would that be so difficult?
Some extra details:
I am using a Stored Procedure - which means I can not change the Query - The Stored Procedures are maintained by someone else.
Stored procedure (which works):
#Query(value = "STORED_PROC :a, :b", nativeQuery = true)
List<List<String>> execStoredProc(#Param("a") String a, #Param("b") String b);
Stored procedure that does not work, because I have more fields in the entity that the Procedure return, because I need those fields in other stored procedures:
#Query(value = "STORED_PROC :a, :b", nativeQuery = true)
List<TestEntity> execStoredProc(#Param("a") String a, #Param("b") String b);
When I remove those field the function works - but I need those fields in other part of my program - and I hoped I could use the same #Entity
Database I am using is MSSQL Database:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
Simply add the missing columns as null:
#Query(value = "SELECT NULL AS ID, NULL AS ID1, ID2, NULL AS ID3 from DATABASE", nativeQuery = true)
List<TestEntity> testNativeQuery ();
I'm working on a spring boot project, there I have two tables that are related to each other with OneToMany relationship
public class PackGroupEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
private Double qty;
private Integer packingNr;
#Temporal(TemporalType.TIMESTAMP)
private Date deliveredTime;
#OneToMany(mappedBy = "packGroup", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<PackArticlesEntity> packArticles= new ArrayList<>();
}
And
public class PackArticlesEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Double qty;
private Double confirmedName;
#Enumerated(EnumType.STRING)
private ArticleStatus status;
private Double weight;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pack_group_id")
private PackGroupEntity packGroup;
}
And I insert data on these two tables in a loop, first I group the articles by packing number for which I will create a PackGroup that has a list of articles:
Map<Integer, List<RecivedArticlesDTO >> groupedArticles =
recivedArticlesListDTO.stream().collect(Collectors.groupingBy(RecivedArticlesDTO::getPackingNr));
for (Map.Entry<Integer, List<RecivedArticlesDTO>> entry : groupedArticles.entrySet()) {
List<RecivedArticlesDTO > groups = entry.getValue();
PackGroupEntity packGroup = new PackGroupEntity();
packGroup.setPackingNr(entry.getKey())
//some manipulations and setting data for each field
List<PackArticlesEntity> listWithArticles = new ArrayList<>();
groups.forEach(pack -> {
PackArticlesEntity packArticle= new PackArticlesEntity();
packArticles.setQty(pack.getQty);
//some manipulations and setting data for each field
listWithArticles.add(packArticles);
}
packGroup.setPackArticles(listWithArticles);
// here I have to save the data using native query
packGroupService.savePackGroupData(packGroup);
}
In this way, it is so slow so I wanted to do it on the native query.
The problem is that I have many packGroups a many packArticles that needs to be saved. I was thinking to somehow do only one connection with DB to send the list of pack groups and pack articles to save, but I don't know how to do this on native queries. This here is just for one pack_group but yet I don't know how to pass packArticles on a native query since it's a list
#Query(value = "insert into pack_group " +
" (id,packing_nr, description, qty, deliveredTime, packArticles) " +
" values (1?, 2?, 3?, 4?, 5?, 6?)", nativeQuery = true)
void savePackGroupData(id, packing_nr, description, qty, packArticles);
Can someone help with this, please?
EDIT:
I want to return the id from insert on
String query = String.format("insert into pack_group(group, remark, description ) " +
"values ( %s, %s, %s)", "x","y","z" );
Query q = entityManager.createNativeQuery(query );
BigInteger biid = (BigInteger) q.getSingleResult();
long id = biid.longValue();
And I get this error com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
To speed things up consider using batch updates. It can be a bit tricky with spring data to get it to work, but it do speed things up considerably when working.
See How to do bulk (multi row) inserts with JpaRepository?
If you wish more control over your insert statements then perhaps spring jdbc is a better option :How to do multiple inserts in database using spring JDBC Template batch?
This is an answer for 'I have a list of articles in which I have to use the reference id of the previous inserted pack group. Can you get that on SQL?' in comment.
You have Main and Detail table. And you want to insert Main first, and Detail second with Id of Main just inserted.
You can use output inserted of SQL Server to get only currently inserted rows.
And you can join it with string_split result to insert into Detail table.
Here's example.
create table Main (
Id int identity(1, 1),
Name nvarchar(50)
);
create table Detail (
MainId int,
Name nvarchar(50)
);
insert into Main (Name) values ('X'); -- To make new inserted Id starts with 2
declare #MainList nvarchar(1000) = 'A,B,C';
declare #DetailList nvarchar(1000) = 'A2,B2,C2';
declare #IdList table (
Seq int identity(1, 1),
Id int
);
-- Insert 3 rows, get all 3 Id using inserted, insert 3 Id to #IdList table
insert into Main (Name)
output inserted.Id into #IdList
select value from string_split(#MainList, ',');
-- Join #IdList table with string_split returned table with Seq
-- Seq of #IdList is auto generated by identity(1, 1)
-- Seq of string_split returned table generated by row_number()
insert into Detail (MainId, Name)
select m.Id MainId, d.value Name
from #IdList m
inner join
(select row_number() over (order by (select 1)) Seq, value
from string_split(#DetailList, ',')
) d
on m.Seq = d.Seq;
Result:
select * from Main;
select * from Detail;
Id Name
--------
1 X
2 A
3 B
4 C
MainId Name
------------
2 A2
3 B2
4 C2
Demo: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=30213ab0cd59fcb7f541c18c738d4dad
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);
AI_DpEntriesRepository.java
public interface AI_DpEntriesRepository extends PagingAndSortingRepository<AI_DpEntries, Long>{
#Query(value = "select a.*,m.description,m.name from AI_DPENTRIES a,"
+ "MEDICALHIERARCHY m where PAGEID in (select pageid from PAGES where caseid=8960)"
+ " and a.HID=m.ID",nativeQuery = true)
Page<AI_DpEntries> getLabAIDpEntries(Pageable pageable);
}
AIDpEntryServiceImpl.java
public class AIDpEntryServiceImpl implements AIDpEntryService{
#Autowired
private AI_DpEntriesRepository aiDpEntryRepository;
#Override
#Cacheable("labdpentries")
public Page<AI_DpEntries> getAIDpEntries(int page,int size) {
Pageable pageRequest = PageRequest.of(page, 5);
Page<AI_DpEntries> pageResult = aiDpEntryRepository.getLabAIDpEntries(pageRequest);
List<AI_DpEntries> dpEntries = pageResult.getContent().stream().collect(Collectors.toList());
return new PageImpl<>(dpEntries, pageRequest, pageResult.getTotalElements());
//return aiDpEntryRepository.getLabAIDpEntries();
}
}
Getting java.sql.SQLSyntaxErrorException: ORA-00904: "A": invalid identifier
From repository call itself. What am i doing wrong? If i pass size parameter value as Integer.MAX_VALUE it returns all records at single time currently. But my requirement is to get 5 records per page
Solution here - There was a need for count query along with native query which would be returning same no. of rows to as returned by native query(PS-Minor change in query from question asked)
#Repository
public interface AI_DpEntriesRepository extends JpaRepository<AI_DpEntries, Long>{
#Query(value = "select a.*,m.description,m.name from AI_DPENTRIES a,
MEDICALHIERARCHY m where PAGEID in (select pageid from PAGES where caseid=8960) and a.HID=m.ID And (a.REVIEW_IND != 'D' OR a.REVIEW_IND IS NULL),
countQuery = "select * from AI_DPENTRIES where PAGEID in (select pageid from PAGES where caseid=8960) and (REVIEW_IND != 'D' OR REVIEW_IND IS NULL)",nativeQuery = true)
public Page<AI_DpEntries> getLabAIDpEntries(Pageable pageable);
}
I have created SQL view in Mysql database. I am writing web service to show list using JPA based on user search entry. Hibernate query is executing correctly in console, but list is not showing when checked in advaced rest client. Please check below for required code:
Entity Class:
#Entity
#Table(name = "tbi_datadiscovery_detail_view"/*, catalog = "timebound"*/)
public class TbiDDDetailView implements java.io.Serializable {
// Fields
#Id
#Column(name = "dd_metric_id")
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign", parameters = #Parameter(name = "property", value = "ddConfigId"))
private Integer ddConfigId;
#Column(name="dd_metric_name")
private String metricName;
#Column(name="dd_type")
private String ddType;
#Column(name="dd_name")
private String ddName;
#Column(name="discovery_id")
private Integer discoveryId;
#Column(name="key_words")
private String keywords;
#OneToOne
#PrimaryKeyJoinColumn
private TbiDDConfigMaster tbiDDConfigMaster;
//setters & getters
}
JPA Repository:
public interface TbiDDDetailViewDao extends CrudRepository<TbiDDDetailView, Integer>, JpaRepository<TbiDDDetailView, Integer> {
#Query("select v from TbiDDDetailView v,TbiDDConfigMaster t where v.ddConfigId = t.ddConfigId and t.domainId=?1 and v.metricName LIKE %?2% or t.keywords LIKE %?2%")
List<TbiDDDetailView> findByDomainIdAndMetricNameLike(Integer domainId,String metricName);
}
Service Implementation:
public TbiDDDetailViewListResponse getViewMatrics(List sortProperties, List sortTypes,
List operator, List value, List property, int page, int limit,
Integer domainId, String searchString) {
TbiDDDetailViewListResponse res = new TbiDDDetailViewListResponse();
List<TbiDDDetailView> tbiDDDetailViews = tbiDDDetailViewDao.findByDomainIdAndMetricNameLike(domainId, searchString);
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery<TbiDDDetailView> qry =cb.createQuery(TbiDDDetailView.class);
Root root = qry.from(TbiDDDetailView.class);
Root config = qry.from(TbiDDConfigMaster.class);
List creteriaList = new ArrayList<>();
Predicate predicate1 = cb.equal(root.get("tbiDDConfigMaster").get("ddConfigId"), config.get("ddConfigId"));
creteriaList.add(predicate1);
Predicate predicate2 = cb.equal(root.get("tbiDDConfigMaster").get("ddConfigId"), domainId);
creteriaList.add(predicate2);
Predicate predicate3 = cb.like(cb.upper(root.get("metricName")),searchString);
creteriaList.add(predicate3);
CriteriaQuery<TbiDDDetailView> criteriaQuery = qry.select(cb.construct(TbiDDDetailView.class, root.get("ddConfigId"),root.get("metricName"),root.get("ddType"),
root.get("ddName"),root.get("discoveryId")));
List<Order> orderList = new ArrayList<>();
orderList = getSort(cb,root,sortProperties, sortTypes, null);
qry.where(cb.and((Predicate[]) creteriaList.toArray(new Predicate[0])));
int start=0;
if(limit != 0)
start=(page-1)*limit;
TypedQuery<TbiDDDetailView> tq = em.createQuery(qry);
tbiDDDetailViews = tq.setFirstResult(start).setMaxResults(limit).getResultList();
TypedQuery<TbiDDDetailView> queryTotal = em.createQuery(criteriaQuery);
long totalRecords = (long) queryTotal.getResultList().size();
List<DDDetailViewResponse> details = new ArrayList<>();
if(tbiDDDetailViews!=null)
{
for(TbiDDDetailView t : tbiDDDetailViews){
DDDetailViewResponse detailView = new DDDetailViewResponse();
detailView.setDdMetricId(t.getDdConfigId());
detailView.setDdMetricName(t.getMetricName());
detailView.setDdType(t.getDdType());
detailView.setDdName(t.getDdName());
detailView.setDiscoveryId(t.getDiscoveryId());
details.add(detailView);
System.out.println("name-->"+t.getDdName()+"------type-------"+t.getDdType()+"-------------id--------------"+t.getDdConfigId()+"---------Metricname-----------"+t.getMetricName());
}
}
res.setRecords(details);
res.setPageNumber(page);
if(limit != 0) {
int Rem = (totalRecords%limit)>0?new Integer(1):0;
int total = (int) (totalRecords/limit + Rem);
res.setTotalPages(total);
log.info("TotalRecords :"+totalRecords + "Total Pages:" +total);
}
return res;
}
When I checked with debugging mode, execution is not going inside for loop only, its directly coming out of loop.
Hibernate query execution in console:
Hibernate: select tbidddetai0_.dd_metric_id as dd_metri1_34_, tbidddetai0_.dd_name as dd_name2_34_, tbidddetai0_.dd_type as dd_type3_34_, tbidddetai0_.discovery_id as discover4_34_, tbidddetai0_.key_words as key_word5_34_, tbidddetai0_.dd_metric_name as dd_metri6_34_ from tbi_datadiscovery_detail_view tbidddetai0_ cross join tbi_dd_config_master tbiddconfi1_ where tbidddetai0_.dd_metric_id=tbiddconfi1_.dd_metric_config_id and tbiddconfi1_.domain_id=? and (tbidddetai0_.dd_metric_name like ?) or tbiddconfi1_.keywords like ?
Hibernate: select tbiddconfi0_.dd_metric_config_id as dd_metri1_35_0_, tbiddconfi0_.created_by as created_2_35_0_, tbiddconfi0_.created_date as created_3_35_0_, tbiddconfi0_.domain_id as domain_i4_35_0_, tbiddconfi0_.is_active as is_activ5_35_0_, tbiddconfi0_.keywords as keywords6_35_0_, tbiddconfi0_.metric_name as metric_n7_35_0_, tbiddconfi0_.modified_by as modified8_35_0_, tbiddconfi0_.modified_date as modified9_35_0_ from tbi_dd_config_master tbiddconfi0_ where tbiddconfi0_.dd_metric_config_id=?
Hibernate: select tbidddetai0_.dd_metric_id as col_0_0_, tbidddetai0_.dd_metric_name as col_1_0_, tbidddetai0_.dd_type as col_2_0_, tbidddetai0_.dd_name as col_3_0_, tbidddetai0_.discovery_id as col_4_0_ from tbi_datadiscovery_detail_view tbidddetai0_ cross join tbi_dd_config_master tbiddconfi1_ where tbidddetai0_.dd_metric_id=tbiddconfi1_.dd_metric_config_id and tbidddetai0_.dd_metric_id=4926 and (upper(tbidddetai0_.dd_metric_name) like ?) limit ?
Hibernate: select tbidddetai0_.dd_metric_id as col_0_0_, tbidddetai0_.dd_metric_name as col_1_0_, tbidddetai0_.dd_type as col_2_0_, tbidddetai0_.dd_name as col_3_0_, tbidddetai0_.discovery_id as col_4_0_ from tbi_datadiscovery_detail_view tbidddetai0_ cross join tbi_dd_config_master tbiddconfi1_ where tbidddetai0_.dd_metric_id=tbiddconfi1_.dd_metric_config_id and tbidddetai0_.dd_metric_id=4926 and (upper(tbidddetai0_.dd_metric_name) like ?)
95953 [http-bio-9090-exec-3] INFO com.acinfotech.timebound.jpa.service.ReportJobsPersistenceServiceImpl - TotalRecords :0Total Pages:0
I have got it working by changing Creteria query with Predicate
Check below code that has worked for me:
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery<TbiDDDetailView> qry =cb.createQuery(TbiDDDetailView.class);
Root root = qry.from(TbiDDDetailView.class);
Root config = qry.from(TbiDDConfigMaster.class);
List creteriaList = new ArrayList<>();
Predicate predicate1 = cb.equal(root.get("tbiDDConfigMaster").get("ddConfigId"), config.get("ddConfigId"));
creteriaList.add(predicate1);
Predicate predicate2 = cb.equal(root.get("tbiDDConfigMaster").get("domainId"), domainId);
creteriaList.add(predicate2);
Predicate predicate3 = cb.or(cb.like(cb.upper(root.get("tbiDDConfigMaster").get("keywords")), "%"+searchString+"%"), cb.like(cb.upper(root.get("metricName")),"%"+searchString+"%"));
CriteriaQuery<TbiDDDetailView> criteriaQuery = qry.select(cb.construct(TbiDDDetailView.class, root.get("ddConfigId"),root.get("metricName"),root.get("ddType"),
root.get("ddName"),root.get("discoveryId")));
qry.where(cb.and((Predicate[]) creteriaList.toArray(new Predicate[0])), predicate3);
TypedQuery<TbiDDDetailView> tq = em.createQuery(qry);
return tq.getResultList();