2

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 {

@Id
@Column(name = "order_int")
private Long id;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "order_int", insertable = false, updatable = false)
private List<OrderEmail> orderEmails;

... }

I am trying to create Projections on this Order , meaning I want to select some specific columns from the Order entity and a column from the OrderEmail entity

But, when I create a projection on the orderEmails field. I don't get the complete list of emails. Which is what I want. Here is the code that I am trying

ProjectionList columnList = Projections.projectionList();
...
columnList.add(Projections.property("id").as("id"));
...
columnList.add(Projections.property("orderemails.EmailAddress").as("email"));

Note, I have also tried columnList.add(Projections.property("orderemails").as("email")); and changed the email (in as) to be a List, but didn't help

Is it possible to create a projection on a List in Hibernate ?

sbolla
  • 671
  • 3
  • 22
  • 39

3 Answers3

1

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();
}
LucasAMV
  • 51
  • 4
0

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.

Firo
  • 30,626
  • 4
  • 55
  • 94
  • Thank you for responding. I am still struggling to do this. I have tried some options as you mentioned. I did eager fetching. I did the aliasToBean transform. THis is working fine. But the display is not combining the emails into a single row. I get the records in separate rows. I want to combine the results and then sent it over to the presentation layer. Can you please provide some examples as to how to group as you were suggesting in the 2nd bullet point? – sbolla Aug 14 '12 at 17:19
0

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

pirho
  • 11,565
  • 12
  • 43
  • 70
Poly Hamza
  • 149
  • 1
  • 8