透过 DAO 方式存取资料,除了用传统的 join 方式处理资料表之间的关联外,也可以直接从物件之间的关联来思考。
下面我们来介绍 DAO 物件之间的关联如何设计。
像我们之前范例的 city
和 user
之间的关联,我们可以想成是一个 city
能够对应多个 user
的一对多关联。
city
的部分跟之前是一样的
object Cities : IntIdTable() {
val name = varchar("name", 50)
}
class City(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<City>(Cities)
var name by Cities.name
}
user
的部分,要改成用 reference
的方式和 city
进行关联。
我们可以用 reference()
和 referencedOn
,来改变 user
的资料表和 DAO 物件宣告
object Users : IntIdTable() {
val city = reference("city", Cities)
val name = varchar("name", 50)
}
class User(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<User>(Users)
var city by City referencedOn Users.city
var name by Users.name
}
宣告完了之後,我们就可以用物件的方式,来处理 city
和 user
之间的关联
SchemaUtils.create(Cities)
SchemaUtils.create(Users)
val paris = City.new {
name = "Paris"
}
User.new {
city = paris
name = "Alice"
}
User
.all()
.forEach {
println("${it.name}: ${it.city.name}")
}
我们就可以看到资料的关联了
Alice: Paris
有时候我们可能会希望某个关联是可选择的,这时我们可以用 optional 的方式,调整我们的资料表和 DAO 物件。
比方说,或许我们会希望允许 user
可以不输入 city
的资料。
我们可以这样调整 user
的资料表和 DAO 物件。
object Users : IntIdTable() {
val city = reference("city", Cities).nullable()
val name = varchar("name", 50)
}
class User(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<User>(Users)
var city by City optionalReferencedOn Users.city
var name by Users.name
}
这样调整之後,我们就可以在写入 user
时略过 city
物件。
SchemaUtils.create(Cities)
SchemaUtils.create(Users)
val paris = City.new {
name = "Paris"
}
User.new {
city = paris
name = "Alice"
}
User.new {
name = "Bob"
}
User
.all()
.forEach {
println("${it.name}: ${it.city?.name}")
}
这样我们印出资料时就会看到
Alice: Paris
Bob: null
到这边,资料的一对多关联就就介绍完毕了。
?.
我们在 optional 关系时,印出 city.name
时,改变了一点程序
${it.city?.name}
这是为什麽呢?
Kotlin 语言在大多数的状况下,都是不会出现 null 的。不过在 optional 的状况下,我们有可能会出现 it.city
为 null 的状态,导致 it.city.name
出错的状况。
幸运的是,Kotlin 在编译时就可以知道这个状况,并且在编译时跳出提示
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type City?
根据他的提示,我们将程序调整成 null-safe
的版本
${it.city?.name}
这样就会在 it.city
为 null
的状况下,不尝试存取 it.city.name
,避免了尝试存取 null
参数的错误。
>>: Day4:梯度下降法(Gradient descent)
昨天介绍到SECRET_KEY,不晓得前一天的东西大家有没有完全了解了呢! 那今天我们再来接着继续介...
一般而言,要安装 Linux,又要保留原本的系统,就得再先了解一下硬碟分割,通常都会以 GRUB ...
本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...
图片来源:*https://www.dcard.tw/f/funny/p/225385728 大家...
大家午安~ 在第 8、9 天我们完成 Data Collection 以及 Google Analy...