美文网首页
Room 引用复杂数据迁移(Migreate)数据库

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

作者: NewNiu | 来源:发表于2021-07-18 15:08 被阅读0次

    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 修改表主键

    相关文章

      网友评论

          本文标题:Room 引用复杂数据迁移(Migreate)数据库

          本文链接:https://www.haomeiwen.com/subject/wqqapltx.html