Change the LAZY fetch type of an entity for a query to EAGER - spring

How to change the LAZY fetch type of an entity for a query to EAGER?
A)Using #EntityGraph
B)Using #NamedEntityGraph
C)Both A & B
D)Not Possible

Related

How to dynamically select columns in Spring Data JPA

I have a typical Spring boot(2.7.6) application with apis' to fetch data in Kotlin.
Assume an entity called Employee
#Entity
data class Employee(
val id: Long,
val name: String,
val age: Int,
val interviewDate: LocalDate,
val joiningDate: LocalDate,
val resignationDate: LocalDate,
val lastWorkingDate: LocalDate
)
For brevity I have removed annotations like #Id etc from above entity class.
One of the APIs which vends out Employee data is such that, in request params I get something like dateType and it will have one of interviewDate/joiningDate/resignationDate/lastWorkingDate. And in request params dateFrom and dateTo, I get the date as an input like 2020-10-01 and 2022-12-30
For example, if api gets input like dateType=interviewDate&dateFrom=2020-10-01&dateTo=2022-12-30 then API has to return all the employee records whose interview_date column has values between 2020-10-01 and 2022-12-30
The example given above is just for ease of explaining. For real use-case have to fetch data from many tables and has many joins(inner/left/right).
Based on the input, what is the better way to select columns dynamically in repository method?
I tried Specification Criteria API, but it was a dead end because I cannot use joins as there is no mapping between Entities like #OneToMany etc.
I am trying with #Query to get data but have to duplicate lots of lines of sql for each condition.
Example of one of the queries I have written in repository class is like below:
#Query(
"""
select
t.a as A,
t.b as B,
tt.c as C,
p.d as D,
p.e as E
from Employee p
join Department t on p.some_id = t.id
join PersonalData tt on tt.id = t.some_id
left outer join SalaryInformation ps on p.id = ps.come_id
left outer join ManagerInformation sbt on p.some_id = sbt.id
. few more joins here
.
.
where p.id= :id and p.interviewDate>=:dateFrom and p.interviewDate<=:dateTo
""" ,
nativeQuery = true
)
fun findByEmployeeIdForInterviewDate(employeeId: Long, dateFrom:String, dateTo: String, pageable: Pageable): Slice<EmployeeDetailsProjection>
With current approach, I have to repeat this query for remaining date columns which I dont want to as it looks ugly.
Any better suggestions will be really helpful :)
I tried Specification Criteria API, but it was a dead end because I cannot use joins as there is no mapping between Entities like #OneToMany etc.
Hibernate 6 introduces a JPA Criteria extension API which you can use to model joins to entities. To use Hibernate 6 you will have to update to Spring 3 though. For every JPA Criteria interface, Hibernate introduces a sub-interface prefixed with Jpa that contains the Hibernate JPA Criteria extensions. You could do e.g.
JpaEntityJoin<SalaryInformation> ps = ((JpaRoot<?>) root).join(SalaryInformation.class, SqmJoinType.LEFT);
ps.on(cb.equal(root.get("id"), ps.get("comeId")));

Spring data jpa projection could not extract ResultSet

I'm trying to map my entity to projection using the below query but i'm getting error as
Exception : could not extract ResultSet SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
here is the query
#Query("select rf.rfqID as rfqID,rf.creationDate as creationDate," +
"rf.deadLineDate as deadLineDate,rf.details as details," +
"rf.message as message, rf.rfqDoc as rfqDoc," +
"CASE WHEN (rf.creationDate > CURRENT_DATE) THEN 'open' ELSE 'closed' END as status," +
"rf.rfqMembers as rfqMembers " +
"from RFQ rf where rf.createdBy = ?1")
Page<RfqDto> loadAllRfq(String creator, Pageable pageable);
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
here is my projection interface
public interface RfqDto {
String rfqID();
Date creationDate();
Date deadLineDate();
String details();
String message();
String rfqDoc();
String status();
List<RfqMember> rfqMembers();
}
The root cause of your problem is here:
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
As it's explained in the documentation:
The important bit here is that the properties defined here exactly match properties in the aggregate root.
...
The query execution engine creates proxy instances of that interface at runtime for each element returned and forwards calls to the exposed methods to the target object.
So, you can not use spring data jpa projection for your case. You can not use hibernate/jpa projection as well, because it dose not support collections in row results.
You can try to use Blaze-Persistence Entity Views. See for example this answer.

Hibernate : Load all subclasses by single query (single-table inheritance)

We decided to use hibernate inheritance mapping strategy with discriminator ( see 10.1.3 : https://docs.jboss.org/hibernate/orm/5.0/manual/en-US/html/ch10.html#inheritance-tablepersubclass-discriminator ) for loading of relatively small amount of read-only data ( ~ 20 000 rows in single table, 80 entity types, each row contains in average 100 characters).
When application starts hibernate loads these entities via ~80 queries + another ~150 queries is made to establish relationships between them. This is of course time consuming and unnecessary.
I would not mind to load whole table by single query, but how to get entity type mapping right as we use discriminator column ?
Of course there is always option to load & map it manually but we would like to stick with hibernate.
hibernate configuration of abstract entity :
#Entity
#DiscriminatorColumn(name = "DISCRIMINATOR_COLUMN", discriminatorType = DiscriminatorType.STRING, length = 30)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "MAIN_TABLE")
public abstract class ApplicationAbstractEntity
...
subclass configuration example :
#Entity
public class SomeSubEntity extends ApplicationAbstractEntity
...
Load entities for given subclass (this repeats for each subclass, 80 entity types = 80 queries) :
currentHibernateSession.createCriteria(SomeSubEntity.class);
Use setResultTransformer with your custom transformer to map result to your entities.
You can load all your entities with one query like
currentHibernateSession.createCriteria(ApplicationAbstractEntity.class).setResultTransformer(new CustomResultTransformer());

How to set limit for a hibernate query

How can I set a limit to this hql query? When I add the limit keyword in the query, an error is thrown.
#Query("from voucher v where v.voucherType.typeDescription = :typeDescription and v.denomination = :denomination")
public List<Voucher> findByVoucherTypeAndDenomination(#Param("typeDescription") String typeDescription,#Param("denomination") BigDecimal denomination);
When you call your query add the following:
.setFirstResult(firstResult).setMaxResults(limit);
setFirstResult is the (optional) offset, setMaxResults is the limit.
UPDATE
Docs:
http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/Query.html#setMaxResults(int)
If you use entityManager, it can be like:
entityManager.createQuery("yourQuery").setFirstResult(0).setMaxResults(5);
You can use two method of Query object.
setFirstResult() // offset
setMaxResults() // limit
but you can not use it in HQL because limit is database vendor dependent so hibernate doesn't allow it through hql query
Limit was never a supported clause in HQL. You are meant to use setMaxResults().

Linq on a Datasource of list type

I have several entity objects for eg. Customer, Orders which derive from IComparable
and all all mapped to database fields.
I bind the grid at runtime as a List<Customer>, List<Orders> etc.
I am writing a custom column class
where I can get Parent.DataSource (it would always be List<>) but the actual type is unknown. I need to convert that to a list type (maybe IList) so I could write linq queries against the datasource.
something like
IList t = Parent.DataSource as IList
var qry = from cl in t
You should be able to convert your Parent.DataSource into the appropriate type via LINQ's Cast() method, and query against it:
var query = from customer in Parent.DataSource.Cast<Customer>()
where customer.Foo == "Bar"
select customer;
you can use Cast in Linq .
var query = from customers in Parent.DataSource.Cast<Customer>()
select customers;
Cast<Customer> will convert your Parent.DataSource to your corresponding Customer entity

Resources