Room 引用复杂数据迁移(Migreate)数据库

2021-07-18  本文已影响0人  NewNiu

Entity 对象中引用 Date Field

需求:一个搜索列表中点击列表条目后,按点击的时间进行排序,将条目显示到列表第一条或最后一条

Entity类
@Entity(indices = [ Index(value = ["word"],unique = true) ])
data class SearchRecord constructor(
    @PrimaryKey(autoGenerate = true)
    var id : Long
){
    constructor() : this(0)
    var word : String ? = null
}

数据库中显示为


未添加时间字段的时候

这时候点击条目时是不能够再根据id来按顺序更新最新点击的条目了,需要加一个field属性:Date

开始迁移-Migrate Start

首先需要了解Date类型非基本数据类型,需要通过转换,数据库才能识别,具体看下面代码:
class DateConverters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

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

(扩展)Entity 对象中引用 List<String>

这里如List<String>这样的类型也是可以通过转换的,网上一找一大堆,提供一个给大家伙看一下:

// 这里主要是把List<String>和 String 进行转换,
//room 不能直接对List<String>进行转换,但可以保存String ,
//我们可以通过Gson()来对List<String>和String进行互相转换
class StringTypeConverter {

    private val gson = Gson()
    private val type = object : TypeToken<List<String>>(){}.type
    @TypeConverter
    fun stringToList(str : String?) : List<String>{
        return if (str?.isNotBlank() == true){
            gson.fromJson(str,type)
        }else{
            Collections.emptyList()
        }
    }

    @TypeConverter
    fun listToString(list : List<String>?) : String{
        return list?.let {
            var string : String? = null
            if (it.isNotEmpty()){
                string = gson.toJson(list)
            }
            string
        } ?: ""
    }
}

大道同源,所以无论多复杂的数据类型,自己写好转换都不用怕。
当然,这里如果是一个List<Music>也是可以的。
以上List<String>只是一个扩展说明,与Date无关。

接下来需要给我们的Entity对象添加Date类型了:

第一步:

@Entity(indices = [ Index(value = ["word"],unique = true) ])
@TypeConverters(DateConverters::class)// 一定要写-重要(了解这个类看第二步)
data class SearchRecord constructor(
    @PrimaryKey(autoGenerate = true)
    var id : Long,
    var last_time: Date// 添加的Date类型
){
//    constructor() : this(0)
// 构造器中每次都放一个Date默认值 ,在新数据创建后将直接存在默认值
    constructor() : this(0,Date(System.currentTimeMillis()))
    var word : String ? = null
}

第二步:

//创建转换类
class DateConverters {
  // 将Long类型转换在Date
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }
  // 将Date类型转换在Long
    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time
    }
}

第三步:

//升级database version 1->2
@Database(entities = [ SearchRecord::class ],version = 2,exportSchema = false)
abstract class DataBase : RoomDatabase() {
    abstract fun getSearchWordsDao() : SearchRecordDao
}

object BrowserDBHelper {
    lateinit var database: DataBase
    fun init(context: Context, name: String) {
        database = Room.databaseBuilder(context, DataBase::class.java, name)
            .addMigrations(MIGRATION_1_2)// 这行也要写
//            .fallbackToDestructiveMigration() // 这句作用如果写上,那就不要写addMigrations了,因为这句的意思是强制升级(将原来的表删除再重新创建新表,这样原来表中的数据将被清空,升级上来其实也没什么意义了,不过也可以这样写)
            .build()
    }

// 添加迁移方法
    private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
// 注意:INTEGER类型需要加上not null default,否则可能出现异常
            database.execSQL("ALTER TABLE SearchRecord ADD COLUMN last_time INTEGER NOT NULL DEFAULT 0 ")
        }
    }
}

至此,room给表添加一个Date类型的参数就完成了,最后使用:
创建dao文件

@Dao // database access object
interface SearchRecordDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertWords( words : SearchRecord)

    @Update
    fun updateWords(vararg words : SearchRecord)

    @Delete
    fun deleteWords(vararg words:SearchRecord)

    @Query("DELETE FROM SearchRecord")
    fun deleteAllWords()

    @Query("SELECT * FROM SearchRecord ORDER BY word DESC")
    fun getAllWords() : LiveData<List<SearchRecord>>

    @Query("SELECT * FROM SearchRecord ORDER BY last_time DESC LIMIT :limitNum")
    fun getWords(limitNum : Int) : LiveData<List<SearchRecord>>
}

具体使用方法:

private val searchRepo = SearchRepo()
fun saveWord(word : SearchRecord){
    wordDao?.insertWords(word)
}

fun clearAllWords(){
    wordDao?.deleteAllWords()
}
// 更新数据时重新将时间修改为当前时间
fun updateWord(word : SearchRecord){
    word.last_time = Date(System.currentTimeMillis())
    wordDao?.updateWords(word)
}
// 获取的列表将以Date时间的降序排列返回
fun getWords(limitNum : Int){
    wordDao?.getWords(limitNum)
}
上一个最后数据库迁移后的样子
迁移(升级)成功后的列表

完。

Room相关

Room 修改表主键

上一篇下一篇

猜你喜欢

热点阅读