Hibernate projection property whole object - java

I have a case like this:
Class Foo with two children (A and B), each being Objects.
In Hibernate, if I want to return only a list of the children, I would use projections on my criteria:
criteria.setProjection(Projections.property("A"));
This gives me a list of A objects, but they are all lazy loaded. As soon as I try to access anything other than the id, obviously things go wrong.
My SQL query indeed shows it:
select A from Foo ...
Logically, only my id is filled in, and not the rest of my properties. How do I solve this problem so I get a list of A objects that have everything filled in?
I tried this:
criteria.setResultTransformer(Transformers.aliasToBean(A.class));
but without success.

if you use hql it would be more efficient:
String hql = "SELECT f.A FROM Foo f";
Query query = session.createQuery(hql);
List results = query.list();
Using criteria I would have use this code
Criteria crit = session.createCriteria(Foo.class);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.property("A"));
crit.setProjection(proList);
List As= crit.list();
or this block
Criteria crit = session.createCriteria(Foo.class);
crit.createAlias("A","a").setProjection(Projections.property("a"));
List As= crit.list();

Related

How to do a .filter() in hibernate

In the django orm I can do something like the following:
people = Person.objects.filter(first_name='david')
for person in people:
print person.last_name
How would I do the equivalent in Java Hibernate's orm? So far, I've been able to do a single get, but not a filter clause:
Person p = session.get(Person.class, "david");
What would be the correct way to do this though?
you can use native SQL
session.beginTransaction();
Person p = getSingleResult(session.createNativeQuery("SELECT * FROM People where name = 'david'",Person.class));
session.getTransaction().commit();
and the function getSingleResult would be somthing like this :
public static <T> T getSingleResult(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
you can get a list like this :
List<Person> list = session
.createNativeQuery("SELECT * FROM People", Person.class)
.getResultList();
There are several approaches to do this so here goes:
Lazy way - possibly bad if you have a tons of data is to just load up
the whole list of persons, stream it and apply a filter to it to
filter out objects not matching the given first name.
Use a HQL query (Hibernate Query Language) to create a select query
https://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/chapters/query/hql/HQL.html
Use Hibernate's Criteria API to achieve the above
https://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/chapters/query/criteria/Criteria.html
Alternatively you can even use a native SQL query to do the above.

Return single column from multi-group Hibernate projection

What I want to achieve:
Select a susbset of entities that have a property value that exists in a List of values. This list is returned by another Query.
In plain SQL, this can be easily achieved with subqueries. This is the Criteria query that returns the relevant values:
DetachedCriteria subq = DetachedCriteria.forClass(MyClass.class)
.setProjection(
Projections.projectionList()
.add(Projections.alias(Projections.max("interestingVal"), "interestingVal"))
.add(Projections.groupProperty("someval1"))
.add(Projections.groupProperty("someval2"))
.add(Projections.groupProperty("someval3"))
);
I would then like to select the entities that have a value of interesting_val that was returned by the above query. Like so:
List<MyClass> resultList = sessionFactory.getCurrentSession().createCriteria(MyClass.class)
.add(Subqueries.propertyIn("interestingVal", subq))
.list();
Unfortunately, the subq subquery returns a List of Object-arrays with length 4, since I have 4 Projection values. All projection values seem to be automatically added to the SELECT clause. This results in an
SQLSyntaxErrorException: ORA-00913: too many values.
How can I either tell my second Criteria query to only use the first element in the Object array or only retrieve the first column in my subquery?
Instead of propertyIn try propertiesIn.
String[] vals = new String[]{"interestingVal", "someval1", "someval2", "someval3"};
List<MyClass> resultList = sessionFactory.getCurrentSession().createCriteria(MyClass.class)
.add(Subqueries.propertiesIn(vals, subq))
.list();

Hibernate how to use detachedCriteria with Query Cached

I have a detachedCriteria like this
private final DetachedCriteria DETACHED_CRITERIA_FOR_FILTERING_STUDENTS= DetachedCriteria.forClass(Students.class)
.add(filters)
.add(super.criterionForFilteringStudents)
.setProjection(idProjection())
.setResultTransformer(transformer(Students.class));
Later i use it like normally do i have a Table named RelationShip which have a Integer which is not a foreing key just a Integer column.
final Criteria criteria = session.createCriteria(RelationShip.class)
.add(filters)
.add(Subqueries.propertyIn("c03",DETACHED_CRITERIA_FOR_FILTERING_STUDENTS));
Everything works like a charm but i did realize that this query is completely cached i mean i used like this of course in a different context.
public List<Student>getStudents()
{
final Criteria criteria = session.createCriteria(Students.class)
.add(filters)
.add(super.criterionForFilteringStudents)
.setProjection(idProjection())
.setResultTransformer(transformer(Students.class))
.setCacheable(true)
.setCacheRegion(region);
return criteria.list();
}
Of course i could do something like
public List<RelationShip>getRelationShip()
{
final Criteria criteria = session.createCriteria(RelationShip.class)
.add(filters)
.add(Restrictions.in("c03",getStudents()));
return criteria.list();
}
But i came with this concern how could i use a DetachedCriteria which is a query which is completely cacheable or cached is this possible?
I have try
DETACHED_CRITERIA_FOR_FILTERING_STUDENTS.getExecutableCriteria(session).setCacheable(true).setCacheRegion(region)
But with no success.
Is this possible?

Native Query Result Parameter is Not mapped to Class Modal

I have using the Native Query in JPA Repository and my query is as:
select u.*, max(a.version_no) as versionNo from users u left join andother_table a on u.id=a.user_id where u.title='abc' group by id;
from my Query i get the "versionNo" which is not mapped to mu user modal.I have put this also in our user modal like as
#Transient
private String versionNo;
with is getter/setter.but in view i will get versionNo is null.
Please help me.
It is null because you annotated it as #Transient, so it is not populated with DB values. You can execute the query without mapping the results directly to your class, and populate the class manually (the query will return a list of Object[]). Other than this, I'm not aware of any alternatives (because of #Transient).
List<Object[]> results = session.createNativeQuery("select max(a.version_no) as versionNo, u.* from users u left join andother_table a on u.id=a.user_id where u.title='abc' group by id").list();
List<MyClass> myClasses = new ArrayList<MyClass>();
for (Object[] result : results) {
MyClass mc = new MyClass();
...
mc.setVersionNo(result[0]);
mc.setSomethingElse(result[1])
...
myClasses.add(mc);
}
Each entry in results list is an object array representing a row returned by native query. Columns are ordered as you select them, so if you put versionNo in the first place in SELECT clause, it will be available with result[0].

How to retrieve all entity with different column value?

In the following criteria query
Criteria criteria = createLogRecordCriteria(maxId, playerId, playerStatus, userCategory, from, to);
criteria.setFirstResult(offset);
criteria.setMaxResults(limit);
criteria.setProjection(Projections.distinct(Projections.property("player")));
List lst = criteria.list();
return lst;
I retrieve only the set of different players , but I need to retireve all entities with different player value. How can it be done through criteria?
Believe this is the query that you are searching for.
For the below query:
select t from Table t
where t.player IN (select distinct t.player
from Table t
);
if DetachedCriteria is a feasible option, the subCriteria can be passed to the mainCriteria written as below (provided that subCriteria should be defined as a DetachedCriteria):
Criteria subCriteria = Criteria.forClass(Table.class);
subCriteria.setProjection(Projections.distinct(Projections.property("player")));
Criteria mainCriteria = createLogRecordCriteria(maxId, playerId, playerStatus, userCategory, from, to);
mainCriteria.add(Property.forName("t.player").in(subCriteria));
//adding the extra restrictions provided in the Question.
mainCriteria.setFirstResult(offset);
mainCriteria.setMaxResults(limit);
List lst = mainCriteria.list();
return lst;
If not, you have to get the result of 'sub-criteria' and then pass the same (in the form of Object[] or Collection) as the parameter to
> mainCriteria.add(Property.forName("t.player").in(Result_Of_subQuery));
Hope this helps.

Categories