How to work with advanced JPA mappings?
Kotlin JDSL is designed to work seamlessly with various JPA mapping strategies. Here are some examples of how to query entities with advanced mappings like composite keys, inheritance, and embedded IDs.
Composite Keys with @IdClass
@IdClass
When an entity uses @IdClass
for a composite primary key, you can query it by referencing the properties of the entity as usual.
Consider the BookAuthor
entity, which has a composite key consisting of book
and authorId
.
@Entity
@IdClass(BookAuthor.BookAuthorId::class)
class BookAuthor(
@Id
val authorId: Long,
) {
@Id
@ManyToOne
lateinit var book: Book
// ...
}
You can write a query that joins BookAuthor
and refers to its properties, including those that are part of the composite key.
val query = jpql {
select(
path(Author::authorId),
).from(
entity(Author::class),
join(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
)
}
Entity Inheritance
Kotlin JDSL supports querying entities that use JPA inheritance. You can use treat
to downcast to a specific subtype in your queries.
For example, if Employee
is a base class with FullTimeEmployee
as a subclass:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
class Employee(
// ...
)
@Entity
class FullTimeEmployee(
// ...
var annualSalary: EmployeeSalary,
) : Employee(...)
You can write a query that specifically targets FullTimeEmployee
and its properties.
val query = jpql {
update(
entity(FullTimeEmployee::class),
).set(
path(FullTimeEmployee::annualSalary)(EmployeeSalary::value),
path(FullTimeEmployee::annualSalary)(EmployeeSalary::value).times(BigDecimal.valueOf(1.1)),
).where(
path(FullTimeEmployee::employeeId).`in`(employeeIds),
)
}
You can also use type()
to filter by entity type in a where
clause.
val query = jpql {
select(
path(Employee::employeeId),
).from(
entity(Employee::class),
).where(
type(entity(Employee::class)).eq(FullTimeEmployee::class)
)
}
Embedded IDs and Embeddable Types
You can query entities that use @EmbeddedId
or contain @Embedded
objects by chaining path expressions.
If a Book
has an @EmbeddedId
of type Isbn
:
@Entity
class Book(
@EmbeddedId
val isbn: Isbn,
// ...
)
@Embeddable
data class Isbn(
val value: String,
)
You can access the value
of the Isbn
using path(Book::isbn)(Isbn::value)
.
val query = jpql {
select(
path(Book::isbn),
).from(
entity(Book::class),
).where(
path(Book::isbn)(Isbn::value).eq("01"),
)
}
This approach works for both @EmbeddedId
and regular @Embedded
properties.
Last updated