How to use Hibernate criteria without joining the sub-classes - java

I'm trying to use Hibernate criteria without joining the sub-classes. Here is my case:
Notification.hbm.xml has the relation:
<many-to-one name="myObject" class="MyObject" column="MY_OBJECT_UID" not-null="true" index="NOTIFICATIONS_OBJECT" foreign-key="NOTIFICATIONS_OBJECT"/>
my JAVA code:
1. Criteria criteria = session.createCriteria(Notification.class.getName());
2. criteria.createAlias("myObject", "myObject", CriteriaSpecification.LEFT_JOIN);
3. criteria.addOrder(Order.desc("myObject.name").ignoreCase());
4. List<Notification> res = (List<Notification>) criteria.list();
If i remove lines 2 and 3 i get the result without joining MyObject, but if i add them, then the query is massive and doing Join with all of MyObject sub classes (and there are many).
I need a solution to avoid those Hibernate joins. One join for MyObject is OK (although not necessary), but Join to every subClass of it, is bad.
What are my option here?
Thanks.

One solution is to use projection, to query only the field you need
ProjectionList properties = Projections.projectionList();
properties.add(Projections.property("property1").as( "property1"));
...
criteria.setProjection(properties);
criteria.setResultTransformer(new AliasToBeanResultTransformer(Notification.class));
You can map it, to you domain Object but its is better to map it to custom DTO like a NotificationDTO, because it won't be managed entity but simple pojo:
You won't be able to update/ delete it. But if you need the data in "read only" mode its the best solution.

Related

QueryDSL, specify projection for join

I'm trying to use QueryDSL to fetch a collection of entities (table Category) where each entity has a #OneToMany association with an other type of entity (table User), and a join is used to get it all in one go.
Problem is that the second entity (the users) contains CLOB fields which should not be included. I don't want to include them in my query. Given the following QueryDSL query :
JPAQuery<CategoryEntity> baseQuery = new JPAQuery<>(entityManager)
.select(QCategoryEntity.categoryEntity)
.from(QCategoryEntity.categoryEntity)
.leftJoin(QCategoryEntity.categoryEntity.users, QUserEntity.userEntity)
.where(somePredicate);
QueryDSL will generate something like
SELECT categoryen0_.id, (...), useren0_.id, (...)
FROM category categoryen0
LEFT OUTER JOIN user useren0 ON ...
WHERE ...
How can a specific projection be applied to this query such that the CLOB data is excluded?
Notes :
I'm trying to avoid native queries and changing the domain model.
I have not found a way to use Projections on the join
itself.
Using subqueries inside joins is not supported by JPQL hence
it's not supported by QueryDSL either.
Turns out this was not working well due to my use of fetch joins, which prevented me from using projections. Solving it was a matter of using a basic join instead and manually reconstructing the relationship.
Collection<Tuple> tuples = new JPAQuery<>(entityManager)
.select(QCategoryEntity.categoryEntity, Projections.constructor(UserEntity.class, <constructor arguments>)
.from(QCategoryEntity.categoryEntity)
.join(QCategoryEntity.categoryEntity.users, QUserEntity.userEntity)
.where(somePredicate);

Hibernate Result Transformer not working for Critera.scroll

Entity ObjA has a One-To-Many relationship with another entity ObjB.
The following code in my dao works as expected:
Session session = getSessionFactory().openSession();
Criteria criteria = session.createCriteria(ObjA);
//......
criteria.setReadOnly(true);
criteria.setCacheable(false);
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
List<ObjA> results = criteria.list();
To optimize above code (to avoid OutOfMemoryException), I tried using ScrollableResults instead of criteria.list():
//same as above code..
ScrollableResults results = criteria.scroll(ScrollMode.FORWARD_ONLY);
while(results.next()){
ObjA a = results.get()[0];
session.evict(a);
//store 'a' in a collection
}
However, using this approach, I ended up getting individual rows for each ObjB corresponding to ObjA (in a sense, duplicate root entities). I tried not evicting the entity, but still got duplicate rows.
Any idea what I am doing wrong/missing here?
P.S. Hibernate version - 3.5.1-FINAL
Seems like this is a never-ending bug/required enhancement in hibernate.
I ended up using fetch="select" for all one-to-many joins.
Although this increased the db queries, but removed the duplicate root entities.

Hibernate and criteria that return the same items multiple times

I've "Student" and "Class" in relation many to many. In between there is a linking table.
If I want to retrieve all the students with HQL in the following way, everything is fine:
Query queryObject = getSession().createQuery("from Student");
return queryObject.list();
With the above code if there are three students I get a list of three students.
If I use criterias, however, it's fine only as long as there are no associations in the linking table.
Criteria crit = getSession().createCriteria(Student.getClass());
return crit.list();
With the second code, I get three results only when the linking table is empty. However when I add an association, I get 6 results. Looking at the log, Hibernate generates multiple selects. How is it possible?
Can someone explain why does this happen? How can I fix the criteria in order to return the three records only once?
EDIT
In the Student class I mapped in this way:
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(
name="room_student_rel"
, joinColumns={
#JoinColumn(name="id_student")
}
, inverseJoinColumns={
#JoinColumn(name="id_room")
}
)
private List<Room> rooms;
In the room (class) I mapped in this way:
#OneToMany(fetch=FetchType.EAGER, mappedBy="room")
#Fetch(FetchMode.SELECT)
private List<RoomStudent> roomStudents;
To expand on my previous comment, Hibernate will try to select using an outer join when the FetchType is set to EAGER.
See 2.2.5.5 at the following:
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
For the implications of this see here:
Hibernate Criteria returns children multiple times with FetchType.EAGER
Now you can also specify a FetchMode (on your criteria.setFetchMode("assocFiled",FetchMode.LAZY) ) to set it to something other than JOIN or you can use something like criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); to filter the duplicates.
Ideally you should avoid EAGER on your entity mappings and where eager fetching is required enable it explicitly on entity load using some hint or via FetchProfile and then deal with the duplicates if required.

How to apply DISTINCT for Child Object using hibernate criteria

I have object called 'MasterObj'. In that 'MasterObj', I have a child object called 'EmployeeObj'(foreign Key)
The relation ship between 'MasterObj' and 'EmployeeObj' is one to Many.
And my 'MasterObj' had so many duplicate 'employeeObj'
I need a count of MasterObj with DISTINCT or without duplication of emp_SlNo
How can I filter the duplicate emp_SlNo from my MasterObj using hibernate criteria.
Sorry for the my bad english.
Thanks in adance.
After so much of google, finally I got this code:
ProjectionList projList = Projections.projectionList();
projList.add(Projections.property("id.state"));
projList.add(Projections.property("id.uspsCity"));
criteria.setProjection(Projections.distinct(projList));
And it works fine for me.
It eliminates the duplicate child object from parent objects.

How to bulk delete from element collection in jpa

I'm using jpa 2.0 and I have the following entity:
#Entity
public class Folder{
#ElementCollection
#CollectionTable(name="folder_files")
private Set<String> files;
// .....
}
Given a file name, I would like to delete all entries where files == theGivenFileName. In sql it would be something like this:
Delete from folder_files where files = XXX
Is there a way to perform this query using criteria-api?
If not, is there a way to perform this query using jpql?
UPDATE:
I think my question was not clear enough:
Since jpql uses entities (and not tables) I cannot just perform the sql written above plus since I'm using #ElementCollection I don't know how to address this variablr or even deal with it. I would like to delete all entries in that collection (in my case, the files set) which holds a given value, from all entities. Is that possible using jpql or (even better) criteria-api?
The Delete FROM clause requires an Entity, so there is no way to delete from an element collection from what I understand.
You can use a native SQL query, or you can map the element collection as a OneToMany to an Entity instead.
You can use the like query just the syntax is slightly changed.
query = em.createQuery("SELECT i FROM Item i WHERE UPPER(i.name) LIKE :keyword ");
query.setParameter("keyword", "%" + keyword.toUpperCase() + "%");
You can read more on following link,
https://forums.oracle.com/forums/thread.jspa?threadID=423742
Updated:
#Noam you can do it: Like in Criteria API
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
Kindly read more on it at following link:
http://ctpconsulting.github.com/query/1.0.0.Alpha3/criteria.html
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
This cannot be done. Via JPQL it does not work because DELETE statement can only be applied to entities. Excerpt from JPA 2.0 specification:
Bulk update and delete operations apply to entities of a single entity
class (together with its subclasses,if any).
...
delete_statement ::= delete_clause [where_clause]
delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]
Also it doesn't work via Criteria API. CriteriaQuery supports only selecting - not updates or removals.
You have to go for native SQL.

Categories