[Day 10 ]资料和资料之间的多对多关联

除了一对多的关联方式以外,资料和资料间也有可能是多对多的关联方式。

比方说常见的用户标签(tag) 系统,就是一种多对多的关联:每个标签可能对应多个用户,而每个用户也可能被标记上多个不同标签。

要怎麽设计这样的关联呢?我们一起来看看

中间表

多对多关系的处理方式,比较建议的做法是设计一个中间表,每笔资料纪录

比方说,如果我们的资料是

user tag
Alice admin, registered, author
Bob customer, unregistered
Carol customer, registered, reader

那我们的资料表内容可能会是

user
id name
1 Alice
2 Bob
3 Carol
tag
id name
1 admin
2 registered
3 author
4 customer
5 unregistered
6 reader
user_tag
user_id tag_id
1 1
1 2
1 3
2 4
2 5
3 4
3 2
3 6

假设我们需要的用户标签系统,tag 资料表和 DAO 物件如下

object Tags : IntIdTable() {  
    val name = varchar("name", 50)  
}  
  
class Tag(id: EntityID<Int>) : IntEntity(id) {  
    companion object : IntEntityClass<Tag>(Tags)  
    var name by Tags.name  
}

我们定义中间表 user_tag 如下

object UserTag : IntIdTable() {  
    val user = reference("user", Users)  
    val tag = reference("tag", Tags)  
}

利用 via 这个内缀,我们让 usertag 物件与 UserTag 资料表进行关联

class Tag(id: EntityID<Int>) : IntEntity(id) {  
    companion object : IntEntityClass<Tag>(Tags)  
    var name by Tags.name  
 	var users by User via UsersTags  
}

class User(id: EntityID<Int>) : IntEntity(id) {  
    companion object : IntEntityClass<User>(Users)  
    var name by Users.name  
 	var tags by Tag via UsersTags  
}

并且定义 usertag 内容

SchemaUtils.create(Users)  
SchemaUtils.create(Tags)  
val alice = User.new {  
 	name = "Alice"  
}  
val bob = User.new {  
 	name = "Bob"  
}  
val carol = User.new {  
 	name = "Carol"  
}  
val admin = Tag.new {  
 	name = "admin"  
}  
val registered = Tag.new {  
 	name = "registered"  
}  
val author = Tag.new {  
 	name = "author"  
}  
val customer = Tag.new {  
 	name = "customer"  
}  
val unregistered = Tag.new {  
 	name = "unregistered"  
}  
val reader = Tag.new {  
 	name = "reader"  
}

定义完成之後,我们就可以以 DAO 的方式,进行 usertag 的关联了

alice.tags = SizedCollection(listOf(admin, registered, author))  
bob.tags = SizedCollection(listOf(customer, unregistered))  
carol.tags = SizedCollection(listOf(customer, registered, reader))

定义完成之後,我们可以透过 user 来找到所有对应的 tag

carol.tags.forEach { println("tag: ${it.name}") }

上面这段程序码会印出

tag: customer
tag: registered
tag: reader

我们也可以透过 tag 来找到对应的 user

registered.users.forEach { println("user: ${it.name}") }

上面这段程序码会印出

user: Alice
user: Carol

透过 DAO 的方式,以物件的思维,来实作多对多的资料关联语法,个人认为比起透过 query 关联的方式来说,更加直观并且好操作许多。


<<:  远程控制的方法

>>:  【Day15】宽松相等、严格相等以及隐含转型

Day3 Sideproject(作品集) from 0 to 1 -技术选择

关於技术选择 可以先决定也可以题目订了後再看要用什麽 我们因为想顺便学一些比较就业取向的技术 所以就...

【C#】Hash Table

Hash Table是一种有key value的资料结构~ 我们能在Hash Table中存入一个v...

Day28-TypeScript(TS)的命名空间(Namespace)

今天要跟大家讲讲TypeScript(TS)的命名空间(Namespace), 命名空间(Names...

day19 Kotlin coroutine flow with liveData in MVVM

恩,标题不知道怎麽下成中文 在之前的范例里,示范了如何用coroutine做一次性的网路请求,并交结...

Day 18 | Frame Animation

逐格动画Frame Animation 最早期的动画制作方式,使用不同的图片连续拨放 先将图片放入专...