JPA - Force Lazy loading for only a given query - jpa

How do i enforce lazy loading strategy just for a given NamedQuery.
for eg. Consider the below pseudo code (just to explain the case)
I have an entity
#Entity
class Xyz {
int a;
int b;
#Fetch = EAGER
Set<ABC> listOfItems;
}
In this case, we have declared listOfItems to be EAGERLY fetched.
Now suppose , I have an NamedQuery (query="getXyz" , name="select x from Xyz x where a=?")
For this query , i just need the result to be lazy i.e i dont want the listOfItems to be retrieved.
What are the ways by which i can acheive them ?
p.s :
1. I dont want to change the listOfItems to be Lazy in the Entity class
2. I dont want to select specific fields in the query like name="select a,b from Xyz z where a = ? "
Thanks in advance for the suggestions

If you don't want to fetch the Set eagerly you have to define it as lazy. However note that the implementation is permitted to fetch eagerly when you specify lazy.
Quoting the specification:
public enum FetchType
extends java.lang.Enum
Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified.
If you however don't want to fetch such a Set I would as an alternative create a small class to fit your needs:
#Entity
#Table(name = "XYZ")
public class XyzStub
{
int a;
int b;
}
You can query for this using a TypedQuery:
EntityManager em;
//....
TypedQuery<XyzStub> q = em.createNamedQuery("select x from XyzStub x where x.a = :a", XyzStub.class)
q.setParameter("a", a);

If you are using EclipseLink, you can use fetch groups,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/AttributeGroup

Related

Deleting from a standalone index, does not reflect on the index where the deleted entity is used as #IndexedEmbedded

We are using hibernate search 5.9.2.
We have two entities with A and B. A has One-To-Many relationship with B. And we are using them as below:
#Entity
#Indexed(index="master_index")
public class A{
#IndexedEmbedded
private Set<B> b= new HashSet<>(0);
//Setter and getter for b
}
#Entity
#Indexed(index = "b")
public class B{
#ContainedIn
private A a;
//Setter and getter for a
}
One-to-Many relationship is defined under the .hbm files.
Now when some record is deleted from index B directly(but through hibernate process) the same record is not deleted from 'master-index'.
Let us assume I have a record 'xyz' which is available under index B and is also available under 'A' with a relationship like DUDE(data of A) can contain many data like 'xyz'.
DUDE->xyz
The expected result should be the record should delete from index 'b' as well as from the 'master-index'.
Does hibernate search provides a way to handle this situation.
Identified the reason, why this was not working. Will try to provide those findings below:
Initially in my older code, our system was fetching the to be deleted data with a query and then a executeUpdate() was fired and it was not deleting the data using the session.delete(). And due to this the hibernate cache was not aware of the deletion of the object.
Below is the old and new code:
Older Version:
Query query = session.getNamedQuery("deleteBySeqnumRec");
query.setLong("seqnum", seqnum);
int result = query.executeUpdate();
status.setNumOfRows(result);
New Version
DataTO dataTO = selectById(new DataTO, seqnum);
if(!dataTO.isRecNotFound()) {
session.delete(dataTO);
status.setNumOfRows(1);
}
Hibernate Search expects bi-directional associations to be updated consistently on both sides.
This means that, when you delete B, you are expected to remove it from A.b. This will cause a change in entity A, which will trigger reindexing of the entity.
If A wasn't reindexed, it probably means you forgot to remove B from A.b.
Identified the reason, why this was not working. Will try to provide those findings below:
Initially in my older code, our system was fetching the to be deleted data with a query and then a executeUpdate() was fired and it was not deleting the data using the session.delete(). And due to this the hibernate cache was not aware of the deletion of the object.
Below is the old and new code:
Older Version:
Query query = session.getNamedQuery("deleteBySeqnumRec");
query.setLong("seqnum", seqnum);
int result = query.executeUpdate();
status.setNumOfRows(result);
New Version
DataTO dataTO = selectById(new DataTO, seqnum);
if(!dataTO.isRecNotFound()) {
session.delete(dataTO);
status.setNumOfRows(1);
}

JPA eclipselink global batch fetch?

when joining I get one select per row. Solution is batch fetch but I dont want that annotation everywhere...
http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_batchfetch.htm
Why do I even need this? One select per row is awful... How can I set this globally? Cheers
Maybe not the ideal solution, but you may try to use JPA hints along with Java generics:
public <T> TypedQuery<T>
createBatchQuery(String ql, Class<T> clazz, String type, String size, String relation) {
return em.createQuery(jpql, clazz)
.setHint(QueryHints.BATCH_TYPE, type)
.setHint(QueryHints.BATCH_SIZE, size)
.setHint(QueryHints.BATCH, relation);
}
The above query may then be used globally and extended with concrete query implementations according to you needs, i.e.
String jpql = "SELECT c FROM Country c WHERE c.name = :name"; // or #NamedQuery
TypedQuery<Country> q = createBatchQuery(jpql, Country.class, "JOIN", "64", "c.cities");
q.setParameter("name", "Australia");
Country c = q.getSingleResult();
Articles on this topic:
Batch fetching - optimizing object graph loading
EclipseLink/Examples/JPA/QueryOptimization

JPA Entity with multiple resultsets having different columns

I am using JPA with derby database. I want to retrieve two different result sets from the same table onto two entirely different screens.
Screen one displays values using "ScannerReport" bean.
Screen two will display values from ScannerSummaryReport bean.
Both beans needs to have data from same Entity "Scanner" as mentioned in code below.
How to define that result set mapping onto the entity for two different result sets, having different columns in it
A ---> Query query = em.createNativeQuery(<query for scanner report goes here >,"ScannerReport");
query.getResultList();
Now A will execute and instantiate an object of ScannerReport class , fill it up with data .
B ---> Query query = em.createNativeQuery(<query for scanner summary report goes here>,"ScannerSummaryReport");
query.getResultList();
I want somehow to let JPA know that when i execute B, now it needs to instantiate an object of a different class lets say ScannerSummaryReport fill it up with data from A DIFFERENT QUERY ( written to calcuate averages and totals ) and return the result.Again please not both queries will be from same entity Scanner..
#SqlResultSetMapping(
name="ScannerReport",
classes={
#ConstructorResult(
targetClass=com.beans.ScannerReport.class,
columns={
#ColumnResult(name="scanYear", type=Integer.class),
#ColumnResult(name="julianDay", type=Integer.class),
#ColumnResult(name="scannerId", type=String.class),
#ColumnResult(name="startTime", type=Long.class),
#ColumnResult(name="endTime", type=Long.class),
#ColumnResult(name="scanTime", type=Long.class),
}
)
}
)
#Entity
public class Scanner {
// Class implementation goes here
}
So just define two SqlResultSetMappings, using the #SqlResultSetMappings annotation, one for each query. See http://www.datanucleus.org/products/accessplatform_4_0/jpa/annotations.html#SqlResultSetMappings for an example

Spring Data map results

I use Spring Data and I can't find a way to map a #Query results into a DTO. E.g on the query
#Query("select f.a f.b from Foo f")
List<FooStripped> find();
where
public class FooStripped {
String a;
String b;
...
}
I want all the results to be mapped to a list of FooStripped an Object[] is returned.
You can see an example for this in Is there a way to transform objects that spring data repositories return?
But I would not do that to be honest. I would advice you do to this manually in the service/controller level. You can use for this the following framework http://modelmapper.org/ or any other object mapping framework.

JPA EntityManager TypedQuery -- Return a Different Class (ViewModel/DTO) than entity model?

Coming from a Entity Framework Background I can cast my ORM results to a class that contains a subset of the full back-end model's data.
I have a JAX-RS REST Service where I am usually returning something like
MyEntity result = em.createQuery(select e from MyEntity e ... blah blah blah).
I know I can do this:
Object result = em.createQuery(select e.Title, e.Version, e.Date from MyEntity e... blah blah blah).
But can I either a:
Cast my result to a separate class or B name my fields in my createquery such that they are named when returning my JSON?
For example in .Net Land I could do something like....
(select new {Title = e.Title, Version = e.Version})
and then cast this to another type. I tried using a typedquery and casting but I get a "Type X is incompatible with return type Y" type error.
My goal is to return a specific subset (view model/ DTO)of my information for consumption in a specific scenario.
E.g My model is huge and I don't want to return a large amount of the data every time.
Yes, creating non-entity types is possible, using JPA constructor expressions i.e. the NEW keyword:
List<DTO> dtos = em.createQuery("SELECT NEW com.example.DTO( o.title, o.version) FROM Entity o").getResultList();
The DTO must have a constructor with all the relevant fields.
There is no need for casting.