Description
TL;DR: Could the result mapping strategy for DTO projections be changed to always use the DTO and not the domain entity? That would save us a lot of error prone and repetitive work, because in Kotlin null-safety prohibits instantiating the domain entities first, if not all non-null fields are also selected in the query.
Details
From the docs I get that result mapping of DTO projections basically consists of these two facts:
- select only the columns that the DTO defines as attributes
- instantiate the domain entity and then map the domain entity to the DTO.
Effectively this means that the instantiated domain entity sets all fields null
that were not queried. This works in Java, but not in Kotlin, because of null-safety.
For example:
data class Avatar(
@Id
val id: UUID? = null,
val userId: Long,
val avatar: String
)
data class AvatarIdWithUserId(
val id: UUID,
val userId: Long,
)
@Repository
interface AvatarRepository : CoroutineCrudRepository<Avatar, UUID> {
fun findByUserIdIn(ids: Set<Long>): Flow<AvatarIdWithUserId>
}
If there is an avatar for userId
1L
the query findByUserIdIn(setOf(1L))
fails with
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method my.package.Avatar.<init>, parameter avatar
From the docs I understand that to make that work it would require me to write a @Query
annotation, because then the result mapping uses the DTO immediately:
@Query("SELECT id, user_id FROM avatar WHERE user_id IN (:ids)")
fun findByUserIdIn(ids: Set<Long>): Flow<AvatarIdWithUserId>
Obviously, that is error prone and unnecessary work. For instance, a major issue in this example is that the query would fail if ids
is empty. Hence, the caller side must first guarantee that ids
is non empty - which is cumbersome. Hence, it would require us to provide a custom implementation for that simple query to return if ids
is empty.