在Exposed DAO的做法中扩展多对多关系时,如果已经分配了某些无关的对象,就会失败

移动开发 2026-07-08

我正在学习使用DAO方式的Kotlin Exposed。我正在为 EmployeeDepartment之间建立多对多关系。接着我尝试建立连接:

transaction {
    SchemaUtils.create(EmployeeTable, DepartmentTable, EmployeeInDepartmentTable)

    val amy = Employee.new {
        name = "Amy"
    }
    val nick = Employee.new {
        name = "Nick"
    }
    val sales = Department.new {
        name = "Sales"
    }

    nick.departments = SizedCollection(nick.departments + sales)
    amy.departments = SizedCollection(amy.departments + sales)
}

这段代码工作正常,能够正确把 nickamysales 连接起来。

然而,当我尝试用一个员工初始化 sales,然后再添加一个新的时,就会出现问题:

transaction {
    SchemaUtils.create(EmployeeTable, DepartmentTable, EmployeeInDepartmentTable)

    val amy = Employee.new {
        name = "Amy"
    }
    val nick = Employee.new {
        name = "Nick"
    }
    val sales = Department.new {
        name = "Sales"
        employees = SizedCollection(amy) // adding amy in intialization
    }

    nick.departments = SizedCollection(nick.departments + sales)
}

在尝试修改 nick.departments 时会抛出 IllegalStateException: Entity must be inserted

更有趣的是,如果把 nick.departments = SizedCollection(nick.departments + sales) 替换为 nick.departments = SizedCollection(sales)(也就是说,我们根本不去查询Nick的空集合),这次就成功了:

transaction {
    SchemaUtils.create(EmployeeTable, DepartmentTable, EmployeeInDepartmentTable)
    val amy = Employee.new {
        name = "Amy"
    }
    val nick = Employee.new {
        name = "Nick"
    }
    val sales = Department.new {
        name = "Sales"
        employees = SizedCollection(amy) // adding amy in intialization
    }
    nick.departments = SizedCollection(sales) // works, really...
}

这是为什么呢?


我正在使用以下工具和配置:

[versions]
kotlin = "2.4.0"
exposed = "1.3.0"
h2 = "2.4.240"

[libraries]
exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" }
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
h2 = { module = "com.h2database:h2", version.ref = "h2" }

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }

以及以下数据库连接:

Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")

以及以下的DAOs:

object DepartmentTable : IntIdTable() {
    val name = varchar("nam", 50)
}

class Department(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<Department>(DepartmentTable)

    var name by DepartmentTable.name

    var employees by Employee via EmployeeInDepartmentTable
}
object EmployeeTable : IntIdTable() {
    val name = varchar("nam", 50)
}

class Employee(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<Employee>(EmployeeTable)

    var name by EmployeeTable.name

    var departments by Department via EmployeeInDepartmentTable
}
object EmployeeInDepartmentTable : Table() {
    val employee = reference("student", EmployeeTable)
    val department = reference("group", DepartmentTable)
    override val primaryKey = PrimaryKey(employee, department)
}

解决方案

你最初把Nick设置为销售部

并且你最后一行写道

...Nick.Depts + Sales ...那就是Sales + Sales

你应该不能把他在Sales中重复添加 = 出错!

如果在Depts中设置Ref.Integrity(无重复项:)

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章