I am trying to use a native query to avoid n+1 selects with an eagerly fetched @ElementCollection
while limiting the result size at the same time.
Assuming the following (simplified) entities:
@Entity
@Table(name = "message")
class Message(
@Id
var id: String,
var title: String,
var body: String,
var receivedAt: Instant,
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "message_tag")
var tags: MutableSet<Tag> = mutableSetOf()
)
@Embeddable
data class Tag(
@Column(name = "label")
var label: String? = null
)
I create a native query that handles the row limit correctly
SELECT message.id,
message.title,
message.body,
message.received_at,
tag.message_id,
tag.label
FROM (SELECT *
FROM message
WHERE message.title = ?
ORDER BY message.received_at DESC
OFFSET ? ROWS FETCH FIRST ? ROWS ONLY) message
LEFT OUTER JOIN message_tag tag
ON base.id = tag.message_id
Now I want to execute the query and map the result to Message
instances that have the tags
initialized.
I managed to do this with native Hibernate API:
val session = entityManager.unwrap(Session::class.java)
session.createNativeQuery(
"""
SELECT message.id,
message.title,
message.body,
message.received_at,
tag.message_id,
tag.label
FROM (SELECT *
FROM message
WHERE message.title = ?
ORDER BY message.received_at DESC
OFFSET ? ROWS FETCH FIRST ? ROWS ONLY) message
LEFT OUTER JOIN message_tag tag
ON base.id = tag.message_id
"""
)
.apply {
addRoot("message", Message::class.java)
addFetch("tag", "message", "tags")
}
.setParameter(1, "some-title")
.setParameter(2, 0)
.setParameter(3, 10)
.resultList
Is there any way to do this in the standard JPA API? I looked at @SqlResultSetMapping
but that gives me no way to configure an @ElementCollection
mapping.