I am have the following product class
productClass
productID
name
make
title
colors {1..*}.
I'm trying to get
productID, colors and name field only..
I product works for single attirbute but colorList wasn't retrieve.
and worst of all.. when I have a criteria (restrictions.in) it says sql is not form properly.. missing attribute y1_
A good example will be
Hibernate criteria with projection not performing query for #OneToMany mapping
I am trying to get the PAYMENT with expenses intact using project where else he is trying to get some fields in expenses
If you want project any set of attributes for any item of color list, consider use http://github.com/moesio/seimos Here you are an example:
As an example, you can use criteria as follows:
Criteria criteria = session.createCriteria(Cat.class);
criteria.add(Restrictions.like(“description”, “Pap”)
.addOrder(Order.asc(“description”);
Criteria subCriteria = criteria.createCriteria("kind", "kind");
subCriteria.add(Restrictions.eq("description", "persa"));
Criteria anotherSubCriteria = subCriteria.createCriteria("anAssociation","anAssociation");
anotherSubCriteria.add(Restrictions.eq("attribute", "anything"));
criteria.setResultTransformer(new AliasToBeanResultTransformer(Cat.class));
criteria.crateAlias(“kind.anAssociation”, “kind_anAssociation”);
criteria.setProjection(Projections.projectionList()
.add(Projections.alias(Projections.property(“id”), “id”))
.add(Projections.alias(Projections.property(“kind.id”, “kind.id”))
.add(Projections.alias(Projections.property(“kind.anAssocation.attribute”, “kind.anAssociation.attribute”))
List cats = criteria.list();
But if you want save some code, you can use Seimos and code just
Filters filters = new Filters();
filters.add(new Filters(“description”, “Pap”)
.add(new Filter(“description”))
.add(new Filter("kind.description", "persa"))
.add(new Filter("kind.anAssociation.attribute", "anything"));
List<Cat> cats = dao.find(filters);
So, consider use http://github.com/moesio/seimos
If I understand you correctly, then you can use such query for your purposes:
List<Object[]> results = sess.createCriteria(Category.class, "category")
.add(Restrictions.in("category.name", new String[]{"Test1", "Test2"}))
.createAlias("items", "item")
.setProjection(Projections.projectionList()
.add(Projections.property("category.id"), "categoryId")
.add(Projections.property("category.name"), "categoryName")
.add(Projections.property("item.name"))
.add(Projections.property("item.initialPrice")))
.list();
It will return the list of Object[] arrays that represents each row of the result.
I don't know sructure of your Color entity and what fields you need from it thats why I posted example for two default entities: Category and Item (their relationship is one-to-many as in your case).
Instead of array you can use List. For example you can define resrictions in above example in such way:
List<String> inRestrictions = new ArrayList<String>();
inRestrictions.add("Test1");
inRestrictions.add("Test2");
...
.add(Restrictions.in("category.name", inRestrictions))
...
EDIT:
If you need Product object with list of colors for it then fetch only it. If you define correct mapping then Colors list will be fetched with it (lazily or eagerly).
List<Product> results = sess.createCriteria(Product.class)
.add(Restrictions.in("... necessary restrictions")
.list()
Related
I have Entities which contain Collections (OneToMany) which hold Person Entities. A person does not know to which Collection it belongs.
I want to search for MyPersons entities that contain specific Persons.
The problem is that I dont know how to search with criteria when I have a list of Persons that need to be mapped to the MyPerson Entities.
Excuse me for my bad english.
I hope someone can help.
data=Collection.stream().filter(f->f.getName().equals("name")).forEach(i->{
System.out.println();
});
I found a solution:
final CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<MyPersons> query = builder.createQuery(MyPersons.class);
Root<MyPersons> root = query.from(MyPersons.class);
Join<MyPersons, MyNaturalPerson> join = root.join("persons");
ParameterExpression<Collection> persons = builder.parameter(Collection.class);
//Persons = filled with MyPerson Entities
query.where(join.in(persons));
TypedQuery<MyPersons> tq = session.createQuery(query);
List<?> resultList = tq.setParameter(persons, result).getResultList();
List<MyNaturalPerson> finalresult = (List<MyNaturalPerson>) resultList;
Thx to a very similar Question/problem
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.
In my database I have a Test table, with columns: testName, testType
there are 2 different tests with the same type I.e "SUN", so I want only one of them for which I use Distinct in my hibernate / criteria as below, but it still giving me both the types with the same name as "sun".
Criteria crit = session.createCriteria(Test.class);
final ResultTransformer trans = new DistinctRootEntityResultTransformer();
crit.setResultTransformer(trans);
List rsList = trans.transformList(crit.list());
Any idea what could be the reason, or any other way of filtering duplicates.
Use Projections.distinct.
Criteria crit = session.createCriteria(Test.class).setProjection(
Projections.distinct(Projections.projectionList()
.add(Projections.property("type"), "type") )
.setResultTransformer(Transformers.aliasToBean(YourBean.class));
List lst = crit.list();
where YourBean.class has a property "type". The returned list will be List<YourBean>.
Try to use :
cr.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
It work perfectly for me
I finally have found out to get values of other columns:
Criteria criteria = session.createCriteria(Test.class);
ProjectionList projectionList = Projections.projectionList();
ProjectionList projectionList2 = Projections.projectionList();
projectionList2.add(Projections.distinct(projectionList.add(Projections.property("distinctColumn"), "distinctColumn")));
projectionList2.add(Projections.property("col1"), "col1");
projectionList2.add(Projections.property("col2"), "col2");
criteria.setProjection(projectionList2);
criteria.setResultTransformer(Transformers.aliasToBean(Test.class));
List list = criteria.list();
Try to use :
Criteria criteria =
session.createCriteria(Test.class).setProjection(
Projections.distinct(Projections.property("testType")));
List<Test> rsList = criteria.list();
Had the same problem and ended up solving using the Group By projection and then adding in all the columns I needed. For example
Criteria query = session.createCriteria(Class.class)
.setProjection(Projections.projectionList()
.add(Projections.groupProperty("Col1"), "Col1")
.add(Projections.groupProperty("Col2"), "Col2"))
.setResultTransformer(Transformers.aliasToBean(Class.class));
List list = query.list();
Try
setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
Criteria crit = session.createCriteria(Test.class);
List list = crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
Projections provide the result of the marked properties only. but, it creates problem for the child entities. See my post for the real problem I faced it.
Hibernate: Parent and Child relationship data structure
Try using:
criteria.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);
It uses default hashcodes to find matches in results.
Thanks.
Well as the question title says, I am trying to make a projection criteria querying only couple of the table attributes.
So I have a Person Table/class and it has about 40 attributes. I want my criteria to get dynamical number of attributes, lets say 10, 11 or 12 (SQL terms select firstname, lastname from person) and I was doing it like this:
Transaction tx = session.beginTransaction();
Criteria crit = session.createCriteria(Person.class);
crit.setCacheable(true);
ProjectionList projList = Projections.projectionList();
projList.add(Projections.property("id"));
Criterias c = null;
for (int i = 0; i < checked.size(); i++) {
Attribute attr = checked.elementAt(i);
switch (attr) {
case LASTNAME:
projList.add(Projections.property("lastName"));
c = enumMap.get(attr);
if (c.isChanged()) {
String tmp = (String) c.getAnswer();
tmp = tmp.replace('*', '%');
crit.add(Restrictions.like("lastName", tmp));
crit.addOrder(Order.asc("lastName"));
}
case ...THE REST .....
}
crit.setProjection(projList);
retList = crit.list();
tx.commit();
return retList;
and it gives back that the retList elements are not from the Person.class:
INFO [AWT-EventQueue-0] (UserGroupManagerApp.java127) - [Ljava.lang.Object;#14b9b80
FATAL [AWT-EventQueue-0] (Login.java78) - java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to usergroupmanager.model.db.Person
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to usergroupmanager.model.db.Person
Please help, for now I am listing all the 40+ attr, and it takes up querying time and I do not like it. I am looking also an alternative solution which will help me solve this. I read about ResultTransformer but havent found how to use it in my case.
You can use criteria.setResultTransformer()
There's some Transformers provided in Hibernate. If your Person has not any association use this:
criteria.setResultTransformer(Transformers.aliasToBean(Person.class));
But if Person has any association, consider use Seimos at http://github.com/moesio/seimos
A lot of code could be saved if you use it instead Criteria.
[Ljava.lang.Object; cannot be cast to
usergroupmanager.model.db.Person
Says in clean words Object[] cannot be cast to Person. When you do a projection, you will get the attributes you selected as an array of objects instead of a hydrated entity.
Your code is missing the declaration of retlist. I guess it's a raw List which you cast to a List<Person> somewhere. Just replace that with List<Object[]>.
If you use a projection in Hibernate you are not querying all the data Hibernate needs to create the objects. Thus Hibernate cannot create the objects.
Thus the query from a projection just returns an array of the SQL returned from the query ie it returns a s List and you access the fields as plain entries in that array.
I have the Vehicles class and mapping file for it and i want to get all rows from vehicles table ordered by ID desc (I also need the same for my other tables).
I got the following code:
session = HibernateUtil.getSessionFactory().getCurrentSession();
tx = session.beginTransaction();
q = session.createQuery("from Vehicles order by ID DESC");
for (Iterator it=q.iterate(); it.hasNext();){
//some logic
}
But my set isn't ordered by ID and each time it has a different order like RAND() or something. I was wondering what is the easiest way to keep the functionality and just to add order by clause because I have the same syntax on many places...
Try after "q = session.createQuery(...);" part:
List results = q.list()
//loop through results
There is probably something wrong elsewhere, because "sort by id desc" part is correct. Check your database/mapping files if you have correct data types and if indexes are set properly.
I'm assuming your vehicles class looks like this? I'm using JPA here because thats what I know...
class Vehicles {
#Id
#Column(name="vehicles_id")
private int id;
// other stuff here
}
I don't expect your session.createQuery to be different from mine so wouldn't something like this work?
Query q = session.createQuery("select v from Vehicles v order by v.id desc");
Also you could use criteria if you wanted yeah?
class Main {
List<Vehicles> cars;
}
Criteria main = session.createCriteria(Main.class);
Criteria secondary = main.createCriteria("cars");
secondary.addOrder(Order.asc("id"));
Have you tried "from Vehicles v order by v.id desc"? Also another option is to add the comparable interface to the entity and then bring the list created by the query into a sortedset. That's typically what I do when I need to sort.