Hibernate Projections List
Asked Answered
L

3

6

I ned to get only a few column values from the table. So I have used Projections to achieve this. The code works, but I don't think it is effective.

My issue was when I used ProjectionsList & then set the criteria.list to an ArrayList - the Bulletin object is null. I'm not sure how to explain this better. So I will put the code and then please read below:

 List<Bulletin> list = new ArrayList<Bulletin>();
 BulletinList bulletinList = null;

 Criteria criteria = null;

 criteria = this.getSession().createCriteria(Bulletin.class)
            .setProjection(Projections.projectionList()
            .add(Projections.property(bulletinIdAttr))
            .add(Projections.property(docNameAttr))   
            .add(Projections.property(docTypeCodeAttr))
            );        
    criteria.addOrder(Order.desc(createdTimeAttr));

    List<Object> rows = criteria.list();
    for (Object r : rows) {
        Object[] row = (Object[]) r;
        Bulletin bull = new Bulletin();
        bull.setBulletinId((Long) row[0]);
        bull.setDocumentName((String) row[1]);
        bull.setDocumentTypeCode((String) row[2]);
        list.add(bull);
      }

    bulletinList = new BulletinList();
    bulletinList.setBulletins(list);

    return bulletinList;

I just need to set criteria.list to BulletinList (Class that holds a list of Bulletin objects). But when I use projections, Bulletin object is null.

I also was reading another thread to use

setResultTransformer(Transformers.aliasToBean

But that ain't working either. So can someone help in this on how to make the code better.

Thanks

Harish

Lubricious answered 15/6, 2012 at 19:42 Comment(0)
O
5
  1. Projections.property() takes a String as an argument. In the code you provided the value of that String should be the name of a member of the Bulletin class. Presumably bulletinIdAttr, for example, is a String with such a value otherwise you would be getting runtime errors.
  2. When you call setProjection on a Criteria instance you are implicitly setting the ResultTransformer to PROJECTIONS and this is what you want. No need to call setResultTransformer yourself. I would simplify the routine a little like this

    List<Object[]> rows = criteria.list();
    for (Object[] row : rows) {
       Bulletin bull = new Bulletin();
       bull.setBulletinId((Long) row[0]);
       bull.setDocumentName((String) row[1]);
       bull.setDocumentTypeCode((String) row[2]);
       list.add(bull);
    }
    

But that shouldn't make any difference to your results. Have you checked that rows is empty?

Octopod answered 16/6, 2012 at 16:56 Comment(5)
Thanks so much for your reply. As I said my code above is working as expected, but just wanted to know if it was efficient. And yes, Projections.property() takes String as argument. When I tried to use your block of code, I get this error:Lubricious
Type mismatch: cannot convert from element type Object to Object[] on line for (Object[] row : rows). What am I missing here? Please let know.Lubricious
Sorry Harish, my original answer was formatted incorrectly, which made the declaration of rows wrong. It should work as it now.Octopod
This works fine. Thanks much. But can you let know the diff. of using List<Object[]> vs List<Object> & why this is better.Lubricious
It probably doesn't make too much difference once it is compiled. But the code is clearer when you cast the result set once rather than twice. (Once as Object and then once per row as Object[]).Octopod
B
8

You can use

 criteria = this.getSession().createCriteria(Bulletin.class)
            .setProjection(Projections.projectionList()
            .add(Projections.property(bulletinIdAttr),"bulletinIdAttr")
            .add(Projections.property(docNameAttr),"docNameAttr")   
            .add(Projections.property(docTypeCodeAttr),"docTypeCodeAttr")
            );        
criteria.addOrder(Order.desc(createdTimeAttr));
criteria.setResultTransformer(new AliasToBeanResultTransformer(Bulletin.class));
List<Bulletin> bulletinList = criteria.list();

Here criteria.setResultTransformer(new AliasToBeanResultTransformer(Bulletin.class)) will transform your result in the desired POJO class but make sure your POJO class( Bulletin.class in your case) should have appropriate setters to set the values of properties.

Now criteria.list() will return the List of Bulletin POJO class instead of Object.

Brentbrenton answered 7/4, 2014 at 12:51 Comment(2)
No longer on that project. But thanks so much for your effort eventhough it's an old thread.Lubricious
this problem was stuck my way many days, i can't do get all property details using Projections.projectionList(), but now i executed my project used this way, really thanks sir @Shiva AgrawalChinookan
O
5
  1. Projections.property() takes a String as an argument. In the code you provided the value of that String should be the name of a member of the Bulletin class. Presumably bulletinIdAttr, for example, is a String with such a value otherwise you would be getting runtime errors.
  2. When you call setProjection on a Criteria instance you are implicitly setting the ResultTransformer to PROJECTIONS and this is what you want. No need to call setResultTransformer yourself. I would simplify the routine a little like this

    List<Object[]> rows = criteria.list();
    for (Object[] row : rows) {
       Bulletin bull = new Bulletin();
       bull.setBulletinId((Long) row[0]);
       bull.setDocumentName((String) row[1]);
       bull.setDocumentTypeCode((String) row[2]);
       list.add(bull);
    }
    

But that shouldn't make any difference to your results. Have you checked that rows is empty?

Octopod answered 16/6, 2012 at 16:56 Comment(5)
Thanks so much for your reply. As I said my code above is working as expected, but just wanted to know if it was efficient. And yes, Projections.property() takes String as argument. When I tried to use your block of code, I get this error:Lubricious
Type mismatch: cannot convert from element type Object to Object[] on line for (Object[] row : rows). What am I missing here? Please let know.Lubricious
Sorry Harish, my original answer was formatted incorrectly, which made the declaration of rows wrong. It should work as it now.Octopod
This works fine. Thanks much. But can you let know the diff. of using List<Object[]> vs List<Object> & why this is better.Lubricious
It probably doesn't make too much difference once it is compiled. But the code is clearer when you cast the result set once rather than twice. (Once as Object and then once per row as Object[]).Octopod
M
3

If you want to do a second search from the same criteria, you have to change or remove the Projection. For example, if you search for the count first:

criteria.setProjection(Projections.rowCount());
Integer count = criteria.list().get(0);

and then want to fetch all the objects:

criteria.setProjection(null);
List<Object> returnedObjects = criteria.list();
Misty answered 23/3, 2016 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.