Kotlin Exposed 使用引用创建实体

Posted

技术标签:

【中文标题】Kotlin Exposed 使用引用创建实体【英文标题】:Kotlin Exposed create entity with reference 【发布时间】:2021-05-12 12:23:05 【问题描述】:

我正在尝试在 Kotlin 上使用 Exposed 编写 CRUD 服务。我有一张包含多对一参考的表格。当我尝试插入时,我得到了

java.lang.IllegalStateException: 上下文中没有事务。

这是表格和实体

object Contacts : IntIdTable("ph_contact")
    var firstName = varchar("first_name",255)
    var lastName = varchar("last_name",255)
    var phone = varchar("phone",4096)
    var email = varchar("email",4096)
    var user = reference("user",Users)


class ContactEntity (id: EntityID<Int>): IntEntity(id)
    companion object : IntEntityClass<ContactEntity>(Contacts)

    var firstName by Contacts.firstName
    var lastName by Contacts.lastName
    var phone by Contacts.phone
    var email by Contacts.email
    var user by UserEntity referencedOn Contacts.user


    fun toContact() = Contact(id.value,user.id.value,firstName,lastName,phone,email)




data class Contact(
    val id: Int,
    val userId: Int,
    val firstName: String,
    val lastName: String,
    val phone: String,
    val email: String
)

这里是创建的服务方法

fun createContact(contact: Contact) = transaction 

        ContactEntity.new 

           this.firstName=contact.firstName
           this.lastName=contact.lastName
           this.phone=contact.phone
           this.email=contact.email
           this.user= UserEntity[contact.userId]

        
    

保存实体后调用toContact()方法报错

var contact = contactEntity.toContact()

创建此类实体的正确方法是什么?

【问题讨论】:

【参考方案1】:

您需要在 create 方法的事务中调用 toContact 方法。

记录的嵌套用户记录只能从事务内部懒惰地访问。

我通过让任何数据访问层接口使用我自己的数据类来解决这个问题。暴露的记录和表在该层下保持私有。不要让事务实体在其上方泄漏。

下面的例子用一个嵌套的用户来说明:

object Users : IntIdTable("ph_users") 
    var otherUserData = varchar("other_user_data", 255)


class UserEntity(id: EntityID<Int>) : IntEntity(id) 
    companion object : IntEntityClass<UserEntity>(Users)

    var otherUserData by Users.otherUserData


    fun toUser() = User(id.value, otherUserData)



object Contacts : IntIdTable("ph_contact") 
    var firstName = varchar("first_name", 255)
    var lastName = varchar("last_name", 255)
    var phone = varchar("phone", 4096)
    var email = varchar("email", 4096)
    var user = reference("user", Users)


class ContactEntity(id: EntityID<Int>) : IntEntity(id) 
    companion object : IntEntityClass<ContactEntity>(Contacts)

    var firstName by Contacts.firstName
    var lastName by Contacts.lastName
    var phone by Contacts.phone
    var email by Contacts.email
    var user by UserEntity referencedOn Contacts.user

    fun toContact() = Contact(id.value, user.toUser(), firstName, lastName, phone, email)



data class Contact(
    val id: Int,
    val user: User,
    val firstName: String,
    val lastName: String,
    val phone: String,
    val email: String
)

data class User(
    val id: Int,
    val otherUserData: String
)

class ContactsRepo 

    fun createContact(contact: Contact): Contact = transaction 
        ContactEntity.new 
            this.firstName = contact.firstName
            this.lastName = contact.lastName
            this.phone = contact.phone
            this.email = contact.email
            this.user = UserEntity[contact.user.id]

        .toContact()
    


编辑:另一种方法是不使用引用的用户记录,而是将其保留为用户 ID?但可能您在其他查询中需要此嵌套记录。

【讨论】:

以上是关于Kotlin Exposed 使用引用创建实体的主要内容,如果未能解决你的问题,请参考以下文章

使用 Kotlin Exposed 进行缓存?

Kotlin Exposed 获取更新的行数

如何避免Kotlin暴露的N + 1查询问题。 (通过DAO的Reference.id.value字段获取值时)

如何通过 Exposed 连接到 Google Cloud SQL

尝试使用JetBrains / Exposed连接到MSSQL数据库

Spring Boot Kotlin 暴露存储过程