JPA select master and filter details by the master's property

26 Views Asked by At

I need to figure out how to select master with filtered details depending on the master's property. The method: getMasters(userId: Long, page: Pageable)

The requirement for each Master in result list is that:

  • if the userId equals to master.userId, select only the newest detail with the master (by created) regardless the state
  • if the userId != master.userId and APPROVED detail exists, select only the APPROVED detail with the master
  • if the userId !=master.userId and APPROVED detail does not exist, filter the Master record entirely.

Could you please help me how to achieve this with criteria query, JPQL or native query?

This will be very frequent query with pagination so I'd like to make it as efficient as possible.

I have JPA mapping this way:

@Entity
class Master {
    @Id var pk: Long? = null,
    var userId: Long,
    @OneToMany(mappedBy="master", fetch=FetchType.LAZY var details: MutableList<Detail> = mutableListOf()
}

@Entity
class Detail {
    @Id var pk: Long? = null,
    @Enumerated(EnumType.STRING) var state: State,
    var created: Instant
}

enum class State { DRAFT, APPROVED }

Q1: how to achieve this by criteria query/JPQL or native query?

Q2: is it possible with JPA to return Master filled only with one detail instead of full bag? Maybe with detached entity? At the end, Master is just simple POJO

Thanks a lot!

EDIT: this is the sql I use, but still not there with the criteria builder..

WITH my_masters AS (SELECT r.pk
                    FROM master r
                    WHERE r.user_id = 'tester1'),
     visible_details AS (SELECT v.*
                          FROM detail v
                                   INNER JOIN master r ON v.master_pk = r.pk
                          WHERE (v.master_pk IN (SELECT * FROM my_masters) OR v.state = 'PUBLISHED')),
     latest_detail_pks AS (select v2.master_pk,
                                   max(v2.created) as created
                            from visible_details v2
                            group by v2.master_pk)
select v.*
from visible_details v
         INNER JOIN latest_detail_pks l
                    ON v.master_pk = l.master_pk
                        and v.created = l.created
order by v.created DESC;
0

There are 0 best solutions below