Search code examples
javaspringhibernatejpasqlresultsetmapping

How to Map Result Set of Native Query to Variable in Entity


I have two entities, Users and Annotations, and I want to add a set of results from a query on the Annotations table to a transient variable in the Users entity.

Entities:

Users

@Entity
public class Users {
    @Id
    @GeneratedValue
    @Column(name="user_id")
    private Long userId;

    @Column(name="username", unique=true, nullable=false)
    private String username;

    @Transient
    private Set<Annotation> annotations;
    .....

Annotations

@Entity
@Table(name="Annotation")
public class Annotation {

    @Id
    @GeneratedValue
    @Column(name="anno_id")
    private Long annoId;

    @Column(name="user_id", nullable=false)
    private Long userId;

    @Enumerated(EnumType.STRING)
    @Column(name="access_control", nullable=false)
    private Access accessControl;

    @Column(name="group_id", nullable=true)
    private Long groupId;
    .....

So I want the Set<Annotation> annotations variable to hold results from a query on the Annotations table. This can't simply be a one-to-many mapping, because I have to limit the results in a specific way. In fact, the query is this:

SELECT anno_id, a.user_id, timestamp, is_redacted, access_control, a.group_id, vocabulary_id, key_, value, target_type, target_id, root_type, root_id FROM Annotation AS a 
LEFT JOIN group_membership g ON g.user_id = ?#{ principal?.getId() }
WHERE a.user_id = :id
AND (a.access_control='PUBLIC'
OR (a.access_control='GROUP' AND a.group_id = g.group_id
OR (a.access_control='PRIVATE' AND g.user_id = a.user_id))
GROUP BY a.anno_id

I think this is possible through SQLResultSetMapping, however, it seems as though the results are always mapped to another, distinct entity. Is it possible to extract the set as collection and store it in the way I want?


Solution

  • You cannot use SQLResultSetMapping in this scenario as the results will only be mapped to be distinct entity. What you can do is execute as native query and then get the result as a list of object array. You can then construct the desired object that you need.

            Query query = entityManager
                    .createNativeQuery("SELECT anno_id, a.user_id FROM Annotation AS a"
                            + " LEFT JOIN group_membership g ON g.user_id = ?"
                            + " WHERE a.user_id = ?"
                            + " AND (a.access_control='PUBLIC'"
                            + " OR (a.access_control='GROUP' AND a.group_id = g.group_id)"
                            + " OR (a.access_control='PRIVATE' AND g.user_id = a.user_id))"
                            + " GROUP BY a.anno_id");
            query.setParameter(1, new Long(1));
            query.setParameter(2, new Long(1));
            List<Object[]> list = query.getResultList();
            return list;