What will be the Criteria for following SQL? - java

Can any one help me out with Criteria for following query :
SELECT * From TableA Inner Join TableB On TableA.ID=TableB.ID
I am trying with the following Criteria
Criteria criteria = session.createCriteria(TableA.class);
criteria.setFetchMode("TableB", FetchMode.JOIN);
The above criteria retrives both the table data.
Also if I need only specific columns from TableA how will the criteria Change ?
Thanks for your time.
Edit: TableA has one-to-many relationship with TableB.

Question doesn't make sense. In hibernate, the 2 Tables should actually be entities in which case they would have a relationship between them. Are you trying to randomly join 2 tables and get a result back? If so you have to use sql and use a ResultTransformer to convert the result into objects.
private ResultTransformer getResultsTransformer()
{
ResultTransformer transformer = new AliasToBeanResultTransformer(
MyResultBean.class) {
#Override
public Object transformTuple(Object[] values, String[] aliases)
{
MyResultBean row = new MyResultBean();
for (int i = 0; i < aliases.length; i++)
{
row.set(aliases[i], values[i]);
}
return (row);
}
};
return transformer;
}
Call this as follows:
Query q = session.createSQLQuery(sql);
q.setResultTransformer(getResultsTransformer());
List<MyResultBean> list = q.list();
UPDATE: If Table A has a 1-to-Many with Table B, then I find it easiest to use Alias
Criteria criteria = getSession().createCriteria(TableA.class);
criteria.createAlias("tableB","b");
criteria.add(Restrictions.eqProperty("id", "b.id");
criteria.list();
I hope this helps. Regards,

With JOIN, you need to indicate to Hibernate that you only want the "root entity", whcih is tableA. Add the following to your code:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

Related

Hibernate - sqlQuery map redundant records while using JOIN on OneToMany

I have #OneToMany association between 2 entities (Entity1 To Entity2).
My sqlQueryString consists of next steps:
select ent1.*, ent2.differ_field from Entity1 as ent1 left outer join Entity2 as ent2 on ent1.item_id = ent2.item_id
Adding some subqueries and writing results to some_field2, some_field3 etc.
Execute:
Query sqlQuery = getCurrentSession().createSQLQuery(sqlQueryString)
.setResultTransformer(Transformers.aliasToBean(SomeDto.class));
List list = sqlQuery.list();
and
class SomeDto {
item_id;
some_filed1;
...
differ_field;
...
}
So the result is the List<SomeDto>
Fields which are highlighted with grey are the same.
So what I want is to group by, for example, item_id and
the List<Object> differFieldList would be as aggregation result.
class SomeDto {
...fields...
List<Object> differFieldList;
}
or something like that Map<SomeDto, List<Object>>
I can map it manually but there is a trouble:
When I use sqlQuery.setFirstResult(offset).setMaxResults(limit)
I retrieve limit count of records. But there are redundant rows. After merge I have less count actually.
Thanks in advance!
If you would like to store the query results in a collection of this class:
class SomeDto {
...fields...
List<Object> differFieldList;
}
When using sqlQuery.setFirstResult(offset).setMaxResults(n), the number of records being limited is based on the joined result set. After merging the number of records could be less than expected, and the data in List could also be incomplete.
To get the expected data set, the query needs to be broken down into two.
In first query you simply select data from Entity1
select * from Entity1
Query.setFirstResult(offset).setMaxResults(n) can be used here to limit the records you want to return. If fields from Entity2 needs to be used as condition in this query, you may use exists subquery to join to Entity2 and filter by Entity2 fields.
Once data is returned from the query, you can extract item_id and put them into a collection, and use the collection to query Entity 2:
select item_id, differ_field from Entity2 where item_id in (:itemid)
Query.setParameterList() can be used to set the item id collection returned from first query to the second query. Then you will need to manually map data returned from query 2 to data returned from query 1.
This seems verbose. If JPA #OneToMany mapping is configured between the 2 entity objects, and your query can be written in HQL (you said not possible in comment), you may let Hibernate lazy load Entity2 collection for you automatically, in which case the code can be much cleaner, but behind the scenes Hibernate may generate more query requests to DB while lazy loading the entity sitting at Many side.
The duplicated records are natural from a relational database perspective. To group projection according to Object Oriented principles, you can use a utility like this one:
public void visit(T object, EntityContext entityContext) {
Class<T> clazz = (Class<T>) object.getClass();
ClassId<T> objectClassId = new ClassId<T>(clazz, object.getId());
boolean objectVisited = entityContext.isVisited(objectClassId);
if (!objectVisited) {
entityContext.visit(objectClassId, object);
}
P parent = getParent(object);
if (parent != null) {
Class<P> parentClass = (Class<P>) parent.getClass();
ClassId<P> parentClassId = new ClassId<P>(parentClass, parent.getId());
if (!entityContext.isVisited(parentClassId)) {
setChildren(parent);
}
List<T> children = getChildren(parent);
if (!objectVisited) {
children.add(object);
}
}
}
The code is available on GitHub.

How to return multiple results in a unique mapped or not object JPA

org.hibernate
hibernate-core
4.3.8.Final
org.hibernate
hibernate-entitymanager
4.3.8.Final
My pom.xml
My Problem is: How to make a query like this...
SELECT
TABLE_D.*,
TABLE_A.NAME_A
FROM
TABLE_D
INNER JOIN
TABLE_E
ON TABLE_D.ID_TAB_E = TABLE_D.ID_TAB_D
LEFT JOIN
TABLE_C
ON TABLE_C.ID_TAB_C = TABLE_D.ID_TAB_D
INNER JOIN
TABLE_B
ON TABLE_B.ID_TAB_B = TABLE_C.ID_TAB_C
INNER JOIN
TABLE_A
ON TABLE_A.ID_TAB_A = TABLE_B.ID_TAB_B
WHERE
TABLE_A.NAME_A = "XXXX";
And Return the selected the values TABLE_D and TABLE_A ​​in a unique Object List(ex: Object that i create to take all this fields) (I could create 1 filter, whatever...) in the JPA ? Plz Help.
If you need to return a list of selected columns in HQL you can just write your hql query and return a List of Object array, i.e.:
List<Object[]> result = session.createQuery("select a.field1, b.field2 from EntityA a join a.entityB b").list();
then you can iterate and get values, based on their type (i.e. String):
for (Object[] arr : result) {
String col1 = (String)arr[0];
String col2 = (String)arr[1];
}

JPA CriteriaBuilder - sort by the number of associated entities in a one-to-many relationship

I have two entities Customer and Order in a one-to-many relation.
For each customer I need to count the number of associated orders and sort the results by this number.
In a native postgres query it looks like this:
select cust.id, count(order.id) from customers cust
left outer join orders order
on cust.id = order.customer_id
where .... conditions ...
group by cust.id
order by count desc;
But I must do this using CriteriaBuilder because this query is part of a larger piece of code that uses CriteriaBuilder to put in additional conditions. In Hibernate I would have probably used Projections, but I can't find anything similar in JPA.
Any help in composing the query using CriteraBuilder would be much appreciated.
Thank you in advance.
Supposing that the entity Customer has a OneToMany property like this:
#OneToMany(mappedBy = "customerId")
private Collection<Order> orders;
You can use the following query:
EntityManager em; // to be built or injected
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Customer> customer = cq.from(Customer.class);
CollectionJoin<Customer, Order> orders = customer.join(Customer_.orders, JoinType.LEFT);
cq.select(cb.tuple(customer, cb.count(orders)));
cq.where(... add some predicates here ...);
cq.groupBy(customer.get(Customer_.id));
cq.orderBy(cb.desc(cb.count(orders)));
List<Tuple> result = em.createQuery(cq).getResultList();
for (Tuple t : result) {
Customer c = (Customer) t.get(0);
Long cnt = (Long) t.get(1);
System.out.println("Customer " + c.getName() + " has " + cnt + " orders");
}
The above approach uses Metamodel. If you don't like it, you can replace Customer_.orders with "orders" and Customer_.id with "id".
If the OneToMany property is of another type, replace CollectionJoin with the collection of the proper type (ListJoin, SetJoin, MapJoin).
Use this inside the specification
cq.orderBy(cb.desc(cb.count(orders)));
Also send PageRequest(1, 10, Sort.unsorted()). This is how I did it.
If you are passing the Sort value as unsorted and then override criteria query with your own logic of sorting on your joined entity

How to write following JPQL using Criteria?

Student - Course : OneToMany
JPQL :
select Student from Student student, Course course where
student.name=:STUDENTNAME and (course.courseName=:COURSENAME or
course.courseDuration=courseDuration)
Let us suppose one student might have 10 courses i want to retrieve only two records having Student - Courses(2).
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Student> criteriaQuery = criteriaBuilder.createQuery(Student.class);
Root<Student> studentRoot = criteriaQuery.from(Student.class);
studentRoot.fetch("courses", JoinType.LEFT);
Predicate condition = criteriaBuilder.equal(studentRoot.get("studentName"), "someName");
//how to add course condition here.
criteriaQuery.where(condition);
I Hope your Student entity has relation with Course mapping with property name course in student entity.
Here is Criteria Query
Criteria criteria = getSession().createCriteria(Student.class);
criteria.createAlias("course", "course");
criteria.add(Restrictions.eq("name", STUDENTNAME));
Criterion courseNameCrit = Restrictions.eq("course.courseName", courseName);
Criterion courseDurationCrit = Restrictions.eq("course.courseDuration", courseDuration);
criteria.add(Restrictions.disjunction().add(courseNameCrit).add(courseDurationCrit));
List<Student> studentList = criteria.list();
There is no equivalent of JPA QL “JOIN FETCH” in Criteria API.
JOIN FETCH uses EAGER fetch irrespective of the fetch type specified in the model annotation.
If you are using criteria api, you can call the getter method of child in the dao,so that it gets loaded.

hibernate criteria issue

i have next tables:
Table table1
table1Id
field1
field2
field3
Table table2
table2Id
table2_field1
table2_field2
table2_field3
table1Id
in this method i get Objects from table1 sorted by some field
public List<table1> getMost() {
DetachedCriteria criteria = (DetachedCriteria) DetachedCriteria.forClass(table1.class);
//criteria.add(Restrictions.conjunction());
criteria.addOrder(Order.desc("field1"));
List<table1> myList = (List<table1>) findByCriteria(criteria,
false, 0, 10);//get first 10 elements by some criteria
return myList;
}
then i need to get Objects from database sorted by some field, but these Objects depend on Objects from table1
public Item getTheBest(Long table1Id) {
DetachedCriteria criteria = (DetachedCriteria) DetachedCriteria
.forClass(Item.class);
DetachedCriteria maxQuery = DetachedCriteria.forClass(Item.class);
maxQuery.add(Restrictions.eq("table1Id", table1Id)).setProjection(
Projections.max("table2_field1"));
criteria.add(Restrictions.and(
Restrictions.eq("table1Id", table1Id),
Property.forName("table2_field1").eq(maxQuery)));
List<Item> result = (List<Item>) findByCriteria(criteria, false);
if (result.iterator().hasNext())
return result.iterator().next();
else
return null;
}
what i want to have is method like this:
public Item getTheBest(List<Long> table1Ids)
thus this method composes these two above methods and makes less calculations.
the idea of the method is to have a Collection of Objects, sorted by one criteria and after sorting by this criteria, we choose items by some field.
so how can i do it in hibernate?
What I understood from above is you have 'A Ordered query result and you want to filter it further".
You can do it in native SQL and use hibernate to convert query result to java objects. Following is an example
SELECT
FROM (SELECT t1.a, t1.b FROM table1 t1 {GROUP BY if needed} ORDER BY t1.a) subTable,
table2 t2
WHERE t1.a = SOMETHING
AND t2.x = SOMETHING

Categories

Resources