Joins¶
The DSL supports joins for querying across entity relationships. Every join function has a fetch-join equivalent for eager loading.
Setup¶
@Entity
class Comment(
@ManyToOne val post: Post,
@OneToOne val persona: Persona,
val content: String,
)
@Entity
class Post(
@ManyToOne val persona: Persona,
val title: String,
val content: String,
)
@Entity
class Persona(
val name: String,
val age: Int,
@OneToOne val organisation: Organisation?,
)
@Entity
class Organisation(
val name: String,
val country: String,
)
Single predicate: joinWithPredicate / fetchJoinWithPredicate¶
val commentsFromAlice = Comment::persona.joinWithPredicate { personaJoin, cb ->
Persona::name.equal(personaJoin, cb, "Alice")
}
val commentsOnPost = Comment::post.joinWithPredicate { postJoin, cb ->
Post::title.equal(postJoin, cb, "Hello World")
}
// Eager load the joined entity at the same time
val commentsFromAliceEager = Comment::persona.fetchJoinWithPredicate { personaJoin, cb ->
Persona::name.equal(personaJoin, cb, "Alice")
}
Multiple predicates: joinWithPredicates / fetchJoinWithPredicates¶
Multiple predicates are automatically combined with AND logic.
val commentsOnMatchingPost = Comment::post.joinWithPredicates { postJoin, cb ->
listOf(
Post::title.equal(postJoin, cb, "Hello World"),
Post::content.equal(postJoin, cb, "Some content"),
)
}
val postsByAlice = Post::persona.joinWithPredicates { personaJoin, cb ->
listOf(
Persona::name.equal(personaJoin, cb, "Alice"),
Persona::age.greaterThan(personaJoin, cb, 18),
)
}
Nullable relationships¶
Use the Nullable variants when the relationship property is nullable (e.g. Organisation?).
This avoids a type mismatch - the lambda receives the unwrapped non-nullable type.
// Persona::organisation is Organisation? - use joinNullableWithPredicate
val personasInAcme = Persona::organisation.joinNullableWithPredicate { orgJoin, cb ->
Organisation::name.equal(orgJoin, cb, "Acme Corp")
}
// Multiple predicates on a nullable relationship
val personasInAcmeUK = Persona::organisation.joinNullableWithPredicates { orgJoin, cb ->
listOf(
Organisation::name.equal(orgJoin, cb, "Acme Corp"),
Organisation::country.equal(orgJoin, cb, "UK"),
)
}
// Fetch variant
val personasInAcmeEager = Persona::organisation.fetchJoinNullableWithPredicate { orgJoin, cb ->
Organisation::name.equal(orgJoin, cb, "Acme Corp")
}
Join types¶
All join functions accept an optional JoinType parameter (defaults to INNER):