close

本篇介紹 Room 的一些進階用法

基本上 App 只需要做呈現後端傳來的資料,Database並不會做得太複雜

不過凡事都有例外,多點知識多點武器便可在此世界多存活一點

本篇介紹 TypeConvertersEmbed, Relation

前言

看我的介紹前,建議先去看google document, 裡面會有正確的觀念,

這邊只寫我的看法,請大家多多指教

 

TypeConverters

當Entity使用有點複雜的物件,該物件不為 SQL 可以支援的基本格式,這時我們就可以只用 TypeConverter 來作轉換

以 google 的例子來解釋,

當我們想要存取 Date 格式的物件,因 SQLite 不支援這物件,但後面的操作使用 Date 物件會比較方便(假設來說)。

所以我們需要轉換 Long 的形式給 DB,之後在讀取時再轉為Date格式。

這時應該人有會想到這應該是 VO(view object) 要做的事情啊?

不過我會想到這應該是資料層可以做的事情吧。

Room 提供的方式就是 TypeConverters

使用方式很簡單,以Date來說 建立一個DateConverter

 class DateConverter  {

     @TypeConverter
     fun fromTimestamp(value: Long?): Date? {
         return value?.let { Date(it) }
     }

     @TypeConverter
     fun dateToTimestamp(date: Date?): Long? {
         return date?.time
     }
 }

Function name 可以自訂,但一定要有兩個function,

1. Date -> Long

2. Long ->  Date

並在上面加上@TypeConverter

並在RoomDatabase中添加

 @TypeConverters(DateConverter::class)
 abstract class AppDatabase : RoomDatabase() {
    ...
 }

enum class也可以用此方法處理

 

Embed 

在實際案例中,我們時常碰到database這塊,無論新增資table或新增資料,往往都有重複性質的欄位

如: createAt, updateAt, delete_flag等等, 這些常用的欄位,是否可以抽出來通用呢?

這時我腦子想,就多打幾行就好了,每個table中的欄位都是特殊的不需要通用才對。我只能說看情況囉

看重複性質多高,看使用的table多寡,看是否有code潔癖需要這樣做

Embed annotation 就可以幫我們做到這些

使用情境: 

1. 需要複製已有的table並加以調整。

2. 設計table時,發現有許多想同欄位,且不會有不同用途。如:createAt, updateAt 。

以上面情境可以整理成 當 Entity 與 Pojo 這種單純型式的class可以適用。

以下為我的範例

我們創造兩個table分別為, User, Pet。 他們中都含有一些基本資訊,如name, age, gender, createData 這四個資訊。

把這些資訊做成Info.kt 

 import java.util.*

 data class Info(
     var name: String? = null,
     var age: Int = 0,
     var gender: Gender? = null,
     var createDate: Date? = null
 )

Entity 則如下:

 @Entity
 class User(
     @Embedded(prefix = "user_")
     var info: Info
 ) {
     @PrimaryKey(autoGenerate = true)
     var uid: Int = 0
 }

 

@Entity
 class Pet(
     @Embedded(prefix = "pet_")
     var info: Info?
 ) {
     @PrimaryKey(autoGenerate = true)
     var pid = 0
     var kind: String? = null
     var uid = 0
 }

prefix 則為column name 的前啜字 (可加可不加)

DB 架構如下

螢幕快照 2019-12-13 下午11.26.17.png

 

Relation

當我們需要對多個table做交集(Join)時,以前的方式會用cursor處理,更原始的就直接把table load出來,再自行組回去。

而Room有提供這需求,讓我們簡單攥寫

首先我們先建立一個Pojo UserAndAllPets class

 class UserAndAllPets {

     @Embedded
     var user: User? = null

     @Relation(
         parentColumn = "uid",
         entityColumn = "uid",
         entity = Pet::class)
     var pets: List<Pet?>? = null
 }

parentColumn 為 User 的 uid, 

entityColumn 為 Pet 的 uid, for query的實體物件

這邊我開一個 UserPetDao class出來,不過為了防止類別爆炸也可以放入UserDao裡

 @Dao
 interface UserPetDao {

     @Query("SELECT * FROM User ORDER BY user_createDate")
     fun loadUserAndPets(): LiveData<List<UserAndAllPets>>
 }

使用方式

 AppDatabase.getInstance(application).userPetDao().loadUserAndPets().observe(this@MainActivity, androidx.lifecycle.Observer { list ->
   //TODO print log for debug    
   ...
 }

記得把Log 印下來 資料是否正確

我把 ball 的uid 設定為apple, 而 beer 沒有任何寵物。其結果如下

15787-15787/com.owen.roomsample D/MainActivity: list size: 2 
15787-15787/com.owen.roomsample D/MainActivity: user name: beer 
15787-15787/com.owen.roomsample D/MainActivity: user name: apple 
15787-15787/com.owen.roomsample D/MainActivity: pet: ball

 

專案範例,有興趣的可以看我的sample,看一步步的撰寫的過程

https://gitlab.com/jc7003/roomsample

 

參考資料

https://developer.android.com/reference/android/arch/persistence/room/TypeConverters

https://developer.android.com/reference/android/arch/persistence/room/Relation.html

https://developer.android.com/reference/android/arch/persistence/room/Embedded

 

相關文章

Android Room 介紹 (一)

Android ForginKey

 

 

 

 

arrow
arrow

    Owen Chen 發表在 痞客邦 留言(0) 人氣()