Exposed DAO: Entity Classes and Relationships
Use the DAO API to map tables to entity classes and navigate relationships.
Exposed DAO: Entity Classes and Relationships is a free Kotlin Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is the Exposed DAO Layer?
The Exposed DAO (Data Access Object) layer wraps the Query DSL with an Active Record-style API. You define Entity subclasses that map to table rows, and read/write properties directly on entity instances.
Defining an Entity
Pair a LongIdTable with an Entity subclass. Each entity class has a companion EntityClass that handles queries:
object Users : LongIdTable("users") {
val name = varchar("name", 100)
val email = varchar("email", 255)
}
class User(id: EntityID<Long>) : LongEntity(id) {
companion object : LongEntityClass<User>(Users)
var name by Users.name
var email by Users.email
}Creating an Entity
Use Entity.new { } inside a transaction { } to create a new row and get an entity instance back:
val alice: User = transaction {
User.new {
name = "Alice"
email = "alice@example.com"
}
}Finding Entities
The companion EntityClass provides finder methods: findById(id), all(), and find { condition }:
transaction {
val user: User? = User.findById(1L)
val allUsers: SizedIterable<User> = User.all()
val filtered = User.find { Users.name like "Al%" }.toList()
}Updating an Entity
Read an entity, mutate its properties inside a transaction, and Exposed will emit the UPDATE automatically when the transaction commits:
transaction {
val user = User.findById(1L) ?: error("Not found")
user.name = "Alice Smith"
// UPDATE issued on transaction commit
}Deleting an Entity
Call entity.delete() inside a transaction to remove the corresponding row:
transaction {
User.findById(5L)?.delete()
}One-to-Many Relationships
Reference a parent entity from a child using reference() on the table and a delegated by property on the entity. Access the child list from the parent via referrersOn:
object Posts : LongIdTable("posts") {
val title = varchar("title", 300)
val authorId = reference("author_id", Users)
}
class Post(id: EntityID<Long>) : LongEntity(id) {
companion object : LongEntityClass<Post>(Posts)
var title by Posts.title
var author by User referencedOn Posts.authorId
}
// On User entity:
val posts by Post referrersOn Posts.authorIdMany-to-Many Relationships
Use an intermediate join table. Expose it as an EntityClass and access both sides using via():
object UserRoles : Table("user_roles") {
val user = reference("user_id", Users)
val role = reference("role_id", Roles)
}
// On User entity:
var roles by Role via UserRolesEager vs Lazy Loading
By default, Exposed loads related entities lazily — each access fires a SQL query. Use load() or with() to eager-load relations and avoid N+1 query problems:
transaction {
User.all().with(User::posts).forEach { user ->
println("${user.name}: ${user.posts.count()} posts")
}
}Caching Within a Transaction
Exposed caches entity instances within a transaction. Accessing the same entity by ID multiple times in one transaction returns the same in-memory object — no redundant DB round trips.
When to Use DAO vs Query DSL
Use the DAO layer when you want object-oriented access patterns with relationships. Use the Query DSL for bulk operations, complex joins, aggregations, or when performance matters and you want precise SQL control.
Quick Check
How do you create a new row and immediately get an entity instance using Exposed DAO?
Recap: Exposed DAO — Entity Classes and Relationships
Key takeaways:
- Pair a
LongIdTablewith aLongEntitysubclass; properties delegate to column definitions Entity.new { }— create;findById(),find { },all()— query;entity.delete()— remove- One-to-many:
referencedOn(child side),referrersOn(parent side) - Many-to-many: join table +
via() - Use
with()to eager-load relations and avoid N+1 queries
Frequently asked questions
Is the “Exposed DAO: Entity Classes and Relationships” lesson free?
Yes — the full text of “Exposed DAO: Entity Classes and Relationships” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.
What will I learn in “Exposed DAO: Entity Classes and Relationships”?
Use the DAO API to map tables to entity classes and navigate relationships. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Kotlin Academy?
No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Exposed DAO: Entity Classes and Relationships” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Kotlin Academy lesson?
Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Exposed Setup: Database Connection and Transaction DSL
- Defining Tables with the Table DSL
- CRUD with the Query DSL: insert, select, update, delete
- Exposed DAO: Entity Classes and Relationships