結束了空教室查詢系統的第一階段-「使用者查詢流程」之後,我們第二階段要了解的是 RoomRush 的「資料來源主線」。
首先我們要讀的檔案是- ClassroomSchedule.kt ,這對於我們理解一間教室的一週課表如何表示成 Room Entity 與資料表欄位的部分扮演著很重要的角色。
剛開始寫資料庫時,我們組內討論是將我們的教室課表寫成 CSV 檔案,之後再做進一步的處理。原本我們以為這樣的寫法,對於剛學習 Android 的我們會很困難;然而,更困難的部份反而是:我們還需要把 CSV 資料表的內容,轉換成 Kotlin 裡面的語法,讓程式可以看得懂。
一開始看到 ClassroomSchedule.kt 時,我把它理解成「將 CSV 轉換成 ClassroomSchedule,可能就像是轉換成 Kotlin 的語法來讀取」。但實際了解後才發現,它是 把 CSV 的欄位值解析成 Kotlin 物件,之後存進 Room Database。
classroom,Mon_1,Mon_2,Mon_3,...,Fri_8,ClassroomType
SF131,X,X,X,...,O,Normal
SF204,O,O,O,...,X,Normal
SF337,O,O,X,...,O,Computer
這就是 RoomRush 原始課表資料的一部分。每一列代表一間教室,而 Mon_1、Mon_2 到 Fri_8 分別代表星期一到星期五的各個節次。
ClassroomSchedule.kt負責什麼和 Hermes Agent 一起重讀檔案後,我了解 ClassroomSchedule.kt 是 RoomRush 的課表資料模型,也是 Room Database 的 Entity。
簡單來說,它是 CSV 原始資料與 Kotlin 程式碼之間的橋樑,負責將課表 CSV 的欄位映射成 Kotlin 的屬性,並直接對應到 Room Database 裡的 classroom_schedules 資料表。
仔細剖析程式碼,這份 Entity 主要由以下四個關鍵部分組成:
這份 Entity 主要由以下四個關鍵部分組成:
@Entity(tableName = "classroom_schedules")
data class ClassroomSchedule(...)
ClassroomSchedule 會對應到 Room Database 裡的 classroom_schedules 資料表;@Entity 就是在告訴 Room:這個 class 對應一張資料表。@PrimaryKey
val classroom: String
classroom 是 教室名稱 。例如 SF130、ES301,因為每間教室在資料表裡應該只出現一次,所以可以當主鍵。@ColumnInfo(name = "Mon_1") val mon1: String?
@ColumnInfo(name = "Tue_N") val tueN: String?
@ColumnInfo(name = "Fri_8") val fri8: String?
Mon_1),但 Kotlin 程式碼習慣使用 Camel Case(如 mon1)讀取。而 @ColumnInfo 負責 對應資料庫欄位名稱和 Kotlin 屬性名稱 。補充: mon1 表示星期一第一節, tueN 表示星期二中午, fri8 表示星期五第八節,都是對應到資料表裡面的欄位。
@ColumnInfo(name = "ClassroomType") val classroomType: String?
classroomType 代表教室類型,例如 Normal、Computer 等。這正是前幾天在詳細頁(RoomDetailActivity )中,被我們拿來轉譯成對應的中文(如「一般教室」、「電腦教室」),並判斷是否可飲食。CSV 原始資料
↓
讀取一列教室課表
↓
建立 ClassroomSchedule(Room Entity)
↓
寫入 Room Database
↓
Repository / DAO 取得課表資料
↓
QueryResultViewModel
↓
根據星期+節次找到對應欄位
↓
判斷該時段是否為 X
↓
篩選出可用教室
ClassroomSchedule 是 RoomRush 的 Room Entity,對應到 Room Database 裡的 classroom_schedules 資料表。
每一筆 ClassroomSchedule 代表一間教室的一週課表。
classroom 是主鍵,用來唯一識別教室。Mon_1、Tue_N、Fri_8 等 CSV / 資料表欄位,透過 @ColumnInfo 對應到 Kotlin 屬性 mon1、tueN、fri8。X 代表該時段被佔用,而不是 X 的欄位會被視為可用。classroomType 則代表教室類型,會在詳細頁轉成中文並用來判斷是否可飲食。「一間教室一列、每個節次一個欄位(如 mon1 到 fri8)」 這種橫向展開的資料設計,對「看一間教室整週課表」很直覺。但在後續維護上卻帶來明顯的硬傷:
未來如果想重構程式,可拆為「教室表」與一對多的「時段表記錄」,或將資料轉為縱向儲存,新增時段只需增加資料筆數,完全不需變動資料表結構。
進入資料來源主線後,我第一個看的檔案是 ClassroomSchedule.kt。
這個檔案不像 Activity 那樣控制畫面,而是定義 RoomRush 的課表資料長什麼樣子。每一筆資料代表一間教室,欄位則代表星期一到星期五各節次的使用狀態。
這種設計的好處是直覺:打開一筆教室資料,就能看到它整週每個時段是否被使用。但它也有明顯限制,因為每個時段都被設計成固定欄位。如果未來要增加更多節次、星期六或更複雜的課表規則,就可能需要修改資料表和查詢邏輯。
這讓我開始理解,資料模型不只是「存資料」,也會影響後續功能的彈性與維護成本。
用一句話總結這檔案,我會說:
ClassroomSchedule是 RoomRush 的課表資料模型;一筆資料代表一間教室的一週課表,每個欄位代表某天某節是否可用。
了解 ClassroomSchedule.kt 是如何定義 RoomRush 的課表資料長什麼樣子後。下一個關鍵問題隨之而來:App 到底要怎麼對這張資料表進行讀寫?
作為資料庫與 Kotlin 程式碼之間的「門衛兼翻譯官」,DAO (Data Access Object) 負責定義所有對 classroom_schedules 資料表的操作方法,例如查詢、新增、更新與刪除。
下一篇,我們將拆解 RoomRush 中的 DAO 設計- ClassroomScheduleDao.kt 。