Question about Criteria.createCriteria in Hibernate API - java

So I'm still trying to get myself acquainted with the Hibernate Criteria API, and I have this piece of Java code which I would like to seek clarification over.
Criteria c = super.getSession().createCriteria(PpNnCtDetail.class);
c.add(Restrictions.between("commencementDate", fromDate, toDate);
This part I understand what's happening - putting it in terms of SQL it would be something like - correct me if I'm wrong,
SELECT * FROM PpNnCtDetail WHERE commencementDate >= fromDate AND commencementDate <= toDate;
The problem comes with the code following the two lines above.
c = c.createCriteria("nnContractTbl");
c.createCriteria("progCategory").add(Restrictions.in("progCategoryId", allProgCat));
c.createCriteria("acadOrgTbl");
c.createCriteria("serviceType");
c.createCriteria("campusTbl");
return c.list();
What is the first line trying to accomplish? Is that assignment back to c redundant?
In fact, what are the lines c.createCriteria trying to achieve? What would an equivalent SQL query look like? More importantly, what would c.list() return?

The assignament on c = c.createCriteria("nnContractTbl"); is redundant, createCriteria and almost all Criteria methods modify the instance they're invoked on, and return the instance itself for method chanining. So you can chain calls like this:
return super.getSession().createCriteria(PpNnCtDetail.class)
.add(Restrictions.between("commencementDate", fromDate, toDate)
.createCriteria("nnContractTbl")
.createCriteria("progCategory").add(Restrictions.in("progCategoryId", allProgCat))
.createCriteria("acadOrgTbl")
.createCriteria("serviceType")
.createCriteria("campusTbl")
.list();
And about the result of that sequence, Criteria.createCriteria(association) will result in an inner join between the data already in the criteria and the table designed in the association modelled by the attribute association. It will also "root" (as they state in the Javadocs) the Criteria at the association entity, so that in further calls to createCriteria(association), association refers to an association attribute declared on the last "rooted" entity.
It's a shorthand for Criteria.createCriteria(association, joinType) with joinType CriteriaSpecification.INNER_JOIN.

Those createCriteria as specified above are basically equivalent to an INNER JOIN to the entity passed.
The best way to find answers to your questions (and also learn hibernate in the meantime) is to turn SQL logging on in your hibernate configuration file, and inspect the generated SQL.

Related

JPA select rows with where clause

I know that entityManager.find() method can be used to fetch a row with the primary key.
But I have a requirement to define a common find method which accepts a map having the where clause conditions. In the map, key will be the column name and value will be the column name value of the where clause. This method should return the list of selected rows.
Can some one help me out?
Take a look at: EntityManager.createQuery. If I understand your question correctly, this will allow you to create the query that you would like to execute. You could also, take a look at using a CriteriaBuilder.
find fetches the row respect to the primary key.Now as you want
"common find method which accepts a map having the where clause conditions. In the map, key will be the column name and value will be the column name value of the where clause. This method should return the list of selected rows"
for this you have to go for CriteriaQuery like this :
The following simple Criteria query returns all instances of the Pet entity in the data source:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> allPets = q.getResultList();
The equivalent JPQL query is:
SELECT p FROM Pet p
Moreover i will advise you to go for annotation based mapping in your entities & look for setter & getter for the methods.In that design also you can have customized method by java logic for this go here to read.
Following might be overkill, but is a fairly generic way to approach it utilizing the criteriaBuilder. While I can't paste the code here (work) I created an abstract BaseFilter<Entity> class.
The easy part is then having the implementing objects provide getXX, setXX properties. A getPredicates() was then added to return an ArrayList of predicates that the abstract BaseDAO could then invoke to perform the query.
We worked specifically with the getXX and setXXX so we could reference the elements via eg, get(Entity1_.childObject).get(ChildObject_.grandChildObject) to assist in refactoring. JPA also supports it via string name so you could implement the getPredicates with that.
JPA requires the actual Entity.class reference in their calls it was a bit of fun trying to obtain it. Eventually a google search turned it up.

When use createQuery() and find() methods of EntityManager?

I would like to know the difference between on these methods.
When use the createQuery()and find() methods of EntityManager ?
What the advantages about each of them ?
Thank you for answer me.
You use find when you want to look up an entity by primary key. That means you know exactly what you're looking for, you just want to pull it out of the database.
You use createQuery when you want to find entities using criteria or if you want to use a JPQL statement to define what you get back. So you would use the query when you want to get an entity or collection of entities matching some conditions.
The createQuery method allows you to create a JPQL statement that will be executed. The JPQL statement allowed is much more dynamic than the one executed by find. For example given the following table:
create table CAT(
cat_id integer,
cat_name varchar(40)
)
You could execute a query to find the cat by name.
entityManager.createQuery("select c from Cat c where c.name = :name");
The find method only allows you to retreive an object using its primary key. So to use the find method for the above table:
entityManager.find(Cat.class, new Integer(1));
In a nutshell, createQuery allows you to retrieve entities in a more dynamic fashion, while find limits you to searching for an entity with a known id.

How do I perform a query like this in Hibernate? Joins

I have several objects classes mapped to a database using annotations and need some help working out how to put together a Hibernate query to get the results I want.
I'm using Hibernate 3.6.5. I've been using Criteria, but happy with Query etc if it works!
I'm new to Hibernate (can manage simple Criteria to filter objects by property but the join stuff is all new), so any explanation in the answer (or suggested reading) would be great.
A RawRead has a tagcode field which contains a String.
Checkpoint, IncidentItem and Guard classes all also have a TagCode property.
I want to retrieve all RawRead objects where the TagCode doesn't match any tagcode value from any of the other classes (IncidentItem, Guard, Checkpoint).
A sort of brain dump/psuedo SQL code:
select raw.* from
RAWREADS raw, checkpoints c, GUARDS g, INCIDENTITEMS i
where
raw.tagcode != c.TAGNO
and raw.TAGCODE != g.IDTAG
and raw.TAGCODE != i.IDTAG;
I realise that won't be efficient etc, just an illustration of my thoughts.
Can you suggest what to look at in Hibernate language?
EDIT/Additions:
The RawRead object is mapped to Guard and Checkpoint (has a property called checkpoint and one called guard that are both instances of those classes - both are #ManyToOne).
IncidentItem does not have any mapping to the other classes.
In order to join objects in HQL there has to be a relationship mapped between them in the annotations at the application level. If there are no mapped relationships, you'll need to do a query like this in plain SQL.

A set of questions on Hibernate quering

Please help me with these Hibernate querying issues.
Consider the following structure:
#Entity
class Manager {
#OneToMany
List<Project> projects;
}
0) there are 2 possible ways of dynamic fetching in HQL:
select m from Manager m join m.projects
from Manager m join fetch m.projects
In my setup second one always returns a result of cartesian product with wrong number of objects in a list, while the first one always returns correct number of entities in a list. But the sql queries look the same. Does this mean that "select" clause removes redundant objects from the list in-memory? In this case its strange to see an advice in a book to use select distinct ... to get rid of redundant entities, while "select" does the job. If this is a wrong assumption than why these 2 queries return different results?
If I utilize dynamic fetching by one of the 2 methods above I see a classic n+1 select problem output in my hibernate SQL log. Indeed, FetchMode annotations (subselect or join) do not have power while fetching dynamically. Do I really can't solve the n+1 problem in this particular case?
Looks like Hibernate Criteria API does not support generics. Am I right? Looks like I have to use JPA Criteria API instead?
Is it possible to write HQL query with an entity name parameter inside? For example "from :myEntityParam p where p.id=1" and call setParameter("myEntityParam", MyClass.class) after this. Actually what I want is generic HQL query to replace multiple non-generic dao's by one generic one.
0) I always use a select clause, because it allows telling what you want to select, and is mandatory in JPQL anyway. If you want to select the managers with their projects, use
select distinct m from Manager m left join fetch m.projects
If you don't use the distinct keyword, the list will contain n instances of each manager (n being the number of projects of the manager): Hibernate returns as many elements as there are rows in the result set.
1) If you want to avoid the n + 1 problem, fetch the other association in the same query:
select distinct m from Manager m
left join fetch m.projects
left join fetch m.boss
You may also configure batch fetching to load 10 bosses (for example) at a time when the first boss is accessed. Search for "batch fetching" in the reference doc.
2) The whole Hibernate API is not generified. It's been made on JDK 1.4, before generics. That doesn't mean it isn't useful.
3) No. HQL query parameters are, in the end, prepared statement parameters. You must use String concatenation to do this.

Does Hibernate's Criteria API still not support nested relations

I'd like to use Hibernate's Criteria API for precisely what everybody says is probably its most likely use case, applying complex search criteria. Problem is, the table that I want to query against is not composed entirely of primitive values, but partially from other objects, and I need to query against those object's id's.
I found this article from 2 years ago that suggests it's not possible. Here's how I tried it to no avail, there are other aspect of Hibernate where I know of where this sort of dot notation is supported within string literals to indicate object nesting.
if (!lookupBean.getCompanyInput().equals("")) {
criteria.add(Restrictions.like("company.company", lookupBean.getCompanyInput() + "%"));
}
EDIT:
Here's my correctly factored code for accomplishing what I was trying above, using the suggestion from the first answer below; note that I am even using an additional createCriteria call to order on an attribute in yet another associated object/table:
if (!lookupBean.getCompanyValue().equals("")) {
criteria.createCriteria("company").add(
Restrictions.like("company", lookupBean.getCompanyValue() + "%"));
}
List<TrailerDetail> tdList =
criteria.createCriteria("location").addOrder(Order.asc("location")).list();
Not entirely sure I follow your example, but it's certainly possible to specify filter conditions on an associated entity, simply by nesting Criteria objects to form a tree. For example, if I have an entity called Order with a many-to-one relationship to a User entity, I can find all orders for a user named Fred with a query like this:
List<Order> orders = session.createCriteria(Order.class)
.createCriteria("user")
.add(eq("name", "fred"))
.list();
If you're talking about an entity that has a relationship to itself, that should work as well. You can also replace "name" with "id" if you need to filter on the ID of an associated object.

Categories