Marshall Walker
Marshall Walker

Reputation: 363

How to do a OneToOne relation using Exposed

I'm trying to do a OneToOne relation between two tables using Exposed, I've created a User table and a UserSettings Table, I'd like to have the User table reference the UserSettings table. My question is how do I create the reference and create a user that has referenced settings?

UserTable

object UserTable : IntIdTable("user") {
    val username = varchar("username", 16)
    val email = varchar("email", 254)
    val password = varchar("password_hash", 60)
    val settings = reference("id", UserSettingsTable)
}

UserEntity

class User(id: EntityID<Int>): IntEntity(id), Principal {

    companion object : IntEntityClass<User>(UserTable)

    var username by UserTable.username
    var email by UserTable.email
    var password by UserTable.password
    val settings by UserSettings referrersOn UserTable.settings
}

SettingsTable

object UserSettingsTable : IntIdTable("user_settings") {
    var themeName = varchar("theme_name", 16).clientDefault {"dark"}
}

SettingsEntity

open class UserSettings(id: EntityID<Int>) : IntEntity(id) {

    companion object : IntEntityClass<UserSettings>(UserSettingsTable)

    var themeName by UserSettingsTable.themeName
}

This is what I was attempting to do to create an entry

User.new {
    email = "[email protected]"
    username = "Someone"
    password = "test"
}.also { newUser ->
    UserSettings.new(newUser.id.value) {
        themeName = "dark"
    }
}

Upvotes: 3

Views: 2460

Answers (1)

sedovav
sedovav

Reputation: 2046

Here is a sample that I haven't tested:

object UserSettingsTable : IntIdTable("user_settings") {
    var themeName = varchar("theme_name", 16).clientDefault {"dark"}
}

object UserTable : IntIdTable("user") {
    val username = varchar("username", 16)
    val email = varchar("email", 254)
    val password = varchar("password_hash", 60)
    val settings = reference("settings", UserSettingsTable)
}

class UserSettings(id: EntityID<Int>) : IntEntity(id) {

    companion object : IntEntityClass<UserSettings>(UserSettingsTable)

    var themeName by UserSettingsTable.themeName
}

class User(id: EntityID<Int>): IntEntity(id) {

    companion object : IntEntityClass<User>(UserTable)

    var username by UserTable.username
    var email by UserTable.email
    var password by UserTable.password
    var settings by UserSettings referencedOn UserTable.settings
}

fun createUser(): User {
    return User.new(1) {
        email = "[email protected]"
        username = "Someone"
        password = "test"
        settings = UserSettings.new(1) { themeName = "dark" }
    }
}

Mind that referencedOn is for simple references, while referrersOn is for collections. Also, there is a limitation in the Exposed

Creating the entity and the reference in the same transaction does only work if you set the id column manually. If you're using UUIDTables and UUIDEntity you can do it like this:

transaction {
 //only works with UUIDTable and UUIDEntity
 StarWarsFilm.new (UUID.randomUUID()){
    ...
    actors = SizedCollection(listOf(actor))
  }
}

Upvotes: 4

Related Questions