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)
}
上一个最后数据库迁移后的样子
迁移(升级)成功后的列表完。
网友评论