Adding a Projection to a List in Hibernate

回眸只為那壹抹淺笑 提交于 2019-12-02 01:31:20

I guess hibernate does not provide such a function. To do this you will have to use database specific functions like LISTAGG from Oracle or GROUP_CONCAT from MySQL. It will group all emails (the String) into one colum, so the result would be:

ORDER_ID     EMAILS
1            nemo@email, dory@email, whale@email
2            spongebob@email, squarepants@email

You can use database specific functions in Hibernate with sqlProjection, so the code will look something like this:

public List<Map> emailsByOrder(){
    Criteria c = session.createCriteria(Order.class,"order");

    Criteria critEmail = c.createCriteria("orderEmails", "emails");
    String listAgg = "LISTAGG({alias}.EMAIL_ADDRESS_COLUMN_NAME, ', ') WITHIN GROUP(ORDER BY {alias}.EMAIL_ADDRESS_COLUMN_NAME ASC) AS EMAILS";
    critEmail.setProjection(Projections.projectionList().add(Projections.groupProperty("order.idOrder").as("ORDER_ID"))
                                                        .add(Projections.sqlProjection(listAgg, new String[]{"EMAILS"}, new Type[]{new StringType()}))); 
    c.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

    return (List<Map>) c.list();
}

it's not possible like you expect. Hibernate has to group the records on the root entity which it only does for complete entities.

  • you could load the complete entity eager fetching the emails and transform it in memory later.
  • you fetch the root entity records duplicated for each email address and group them together in memory

Update:

List<Object[]> results = session.createCriteria(Order.class)
    .joinAlias("orderEmails", "email")
    .setProjection(Projections.projectionList()
        .add(Projections.property("id").as("id"))
        .add(Projections.property("email.EmailAddress").as("email")))
    .list<Object[]>();

Map<int, List<String>> groups = new Hashmap<int, List<String>>();
for (Object[] items : results)
{
    if (groups.containsKey((long)items[0]))
        groups.get((long)items[0]).add((String)items[1]);
    else
        groups.add((long)items[0], new List<String>().add((String)items[1]));
}

return groups;

instead of the map one could also have dtos or something like that.

Poly Hamza

Even it's a little bit late but never too late, You make your normal projection with a list inside then in the end it's possible in hibernate to return one line using this :

.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)

Details here: Criteria.DISTINCT_ROOT_ENTITY vs Projections.distinct

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!