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?
Related
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();
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.
i have a simple Criteria like this
Student has only one School this is just a illustrative example.
private List<Student>getData()
{
final Session session = ...............
final Criteria criteria = session.createCriteria(Student.class);
final Criteria criteria2 = criteria.createCriteria("school","school",JoinType.LEFT_OUTER_JOIN,isNotNull("status"));
return criteria.list();
}
i need the Students even if they not have a School... but if they have the School i need the Status is not NULL.
i was wondering if this
criteria.createCriteria("school","school",JoinType.LEFT_OUTER_JOIN,isNotNull("status"));
filterings using left-outer-join are useless because i am getting the Schools with null status
but if i apply this
final Criteria criteria2 = criteria.createCriteria("school","school",JoinType.LEFT_OUTER_JOIN);
criteria2.add(isNotNull("status"));
it works or if i apply
criteria.createCriteria("school","school",JoinType.INNER_JOIN,isNotNull("status"));
works as well.
my question is
i should never put Criterions or filters in createCriteria o createAlias using left-Outer-Join are they just ignored or how can that be used?
what are the diffs between using in the ON or use the same criterions in regular criteria using .add(
any help is hugely appreciate.
I am relatively new to Hibernate, and I have a problem when adding a "distinct" restriction on my hibernate class.
#Entity
public class TaggedOffer {
private Long tagged_offers_id;
private String brand;
private Long cid;
private Date created_date;
//Getter and Setter and more fields
}
Previously, we were creating a hibernate query as follows:
public DetachedCriteria build(final TaggedOfferRequest request) {
DetachedCriteria criteria = DetachedCriteria.forClass(TaggedOffer.class);
criteria.add(Restrictions.eq("brand", request.getBrand()));
criteria.add(Restrictions.in("cid", request.getCids()));
// sort by date
criteria.addOrder(Property.forName("createdDate").desc());
return criteria;
}
This would create the following (working) SQL query:
select
this_.tagged_offers_id as tagged1_2_3_,
this_.brand as brand2_3_,
this_.cid as cid2_3_,
this_.created_date as created6_2_3_
from
site.tagged_offers this_
where
this_.brand=?
and this_.country_code=?
and this_.cid in (
?, ?
)
order by
this_.created_date desc limit ?
Here comes the tricky part. We now need to ensure that the results that are returned are distinct on the cid field. Meaning, return as many results as possible, providing each record has a unique cid associated with it.
I looked into this in SQL, and it seems that the easiest way to do this is just to have a group by cid in the query. In terms of the hibernate criteria, this is basically what I've been trying:
public DetachedCriteria build(final TaggedOfferRequest request) {
DetachedCriteria criteria = DetachedCriteria.forClass(TaggedOffer.class);
criteria.add(Restrictions.eq("brand", request.getBrand()));
criteria.add(Restrictions.in("cid", request.getCids()));
// sort by date
criteria.addOrder(Property.forName("createdDate").desc());
// ** new ** distinct criteria
criteria.setProjection(Projections.groupProperty("cid"));
return criteria;
}
This almost creates the SQL that I am looking for, but it later throws a class cast exception (as it's just selecting the cid field as opposed to the entire object).
select
this_.cid as y0_
from
site.tagged_offers this_
where
this_.brand=?
and this_.country_code=?
and this_.cid in (
?, ?
)
and tagtype1_.tag_type=?
group by
this_.cid
order by
this_.created_date desc limit ?
And the exception:
java.lang.ClassCastException: java.lang.Long cannot be cast to com.mycompany.site.taggedoffers.dao.model.TaggedOffer
Any idea how I can use projections to do what I want?
Thanks for your help.
Add projections for all columns which you need.
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("cid"));
projectionList.add(Projections.property("tagged_offers_id"));
...
criteria.setProjection(projectionList);
I have a doubt why there is a need to use group by here without any aggregate calculations!!
In case if you use group by with projection , then the particular column used in group by will be included again in fetch sql ignoring even the same column is used already in select statement.
To map the extra columns generated by hibernate due to group by you have to write a field in entity class and marking it as #Transient or you can use setResultTransformer and map to another class
You have the EntityManager.find(Class entityClass, Object primaryKey) method to find a specific row with a primary key.
But how do I find a value in a column that just have unique values and is not a primary key?
You can use appropriate JPQL with TypedQuery.
try {
TypedQuery<Bean> tq = em.createQuery("from Bean WHERE column=?", Bean.class);
Bean result = tq.setParameter(1, "uniqueKey").getSingleResult();
} catch(NoResultException noresult) {
// if there is no result
} catch(NonUniqueResultException notUnique) {
// if more than one result
}
For example, like this:
List<T> results = em.createQuery("SELECT t FROM TABLE t", T.class)
.getResultList();
With parameters:
List<T> results = em.createQuery("SELECT t FROM TABLE t where t.value = :value1")
.setParameter("value1", "some value").getResultList();
For single result replace getResultList() with getSingleResult():
T entity = em.createQuery("SELECT t FROM TABLE t where t.uniqueKey = :value1")
.setParameter("value1", "KEY1").getSingleResult();
One other way is to use Criteria API.
You can use a Query, either JPQL, Criteria, or SQL.
Not sure if your concern is in obtaining cache hits similar to find(). In EclipseLink 2.4 cache indexes were added to allow you to index non-primary key fields and obtain cache hits from JPQL or Criteria.
See,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Indexes
Prior to 2.4 you could use in-memory queries to query the cache on non-id fields.
TL;DR
With in DSL level - JPA no practice mentioned in previous answers
How do I find a value in a column that just have unique values and is not a primary key?
There isn't specification for query with custom field with in root interface of javax.persistence.EntityManager, you need to have criteria base query.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<R> criteriaQuery = criteriaBuilder.createQuery(EntityType.class)
Root<R> root = criteriaQuery.from(type);
criteriaBuilder.and(criteriaBuilder.equal(root.get(your_field), value));
You can also group your predicates together and pass them all together.
andPredicates.add(criteriaBuilder.and(root.get(field).in(child)));
criteriaBuilder.and(andPredicates.toArray(new Predicate[]{});
And calling result(rather single entity or a list of entities) with
entityManager.createQuery(suitable_criteria_query).getSingleResult();
entityManager.createQuery(suitable_criteria_query).getResultList();