Adding a Projection to a List in Hibernate

前端 未结 3 446
深忆病人
深忆病人 2021-01-21 17:39

I have a @Entity called Order in this I have a field or a member variable called orderEmails as show below.

@Entity
@Table(name = \"order\")
public class Order {         


        
相关标签:
3条回答
  • 2021-01-21 17:57

    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

    0 讨论(0)
  • 2021-01-21 18:14

    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.

    0 讨论(0)
  • 2021-01-21 18:24

    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();
    }
    
    0 讨论(0)
提交回复
热议问题