学更好的别人,
做更好的自己。
——《微卡智享》
前言
Room数据库迁移

微卡智享
val MIGRATION_1_2 = object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +"PRIMARY KEY(`id`))")}}val MIGRATION_2_3 = object : Migration(2, 3) {override fun migrate(database: SupportSQLiteDatabase) {database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")}}Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name").addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
妥善处理缺失的迁移路径
Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name").fallbackToDestructiveMigration().build()
警告:在应用的数据库构建器中设置此选项意味着 Room 在尝试执行没有定义迁移路径的迁移时会从数据库表中永久删除所有数据。
如果特定版本的架构历史记录导致迁移路径出现无法解决的问题,请改用 fallbackToDestructiveMigrationFrom()。此方法表示您仅在从特定版本迁移时才希望 Room 回退到破坏性重新创建。
如果您仅在从较高数据库版本迁移到较低数据库版本时才希望 Room 回退到破坏性重新创建,请改用 fallbackToDestructiveMigrationOnDowngrade()。
01
数据库增加新表
package ryb.medicine.database.bean.tableimport androidx.room.Entityimport androidx.room.Indeximport androidx.room.PrimaryKeyimport ryb.medicine.library_common.base.DateTimeUtils/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:10:07* 功能模块说明:*/@Entity(tableName = "t_Bill_TurnOverPick",indices = [Index(value = ["dept_no"]), Index(value = ["bill_no"]),Index(value = ["drugs_code"]), Index(value = ["upload_flag"]),Index(value = ["bill_date"])])class CBillTurnOverPick {//ID@PrimaryKey(autoGenerate = true)var id: Long = 0//科室编码var dept_no: String = ""//科室编码var dept_name: String = ""//来源科室编码var source_dept_no: String = ""//来源科室编码var source_dept_name: String = ""//单号var bill_no: String = ""//单据时间var bill_date: String? = ""//单据类型 0-非清单补药 1-清单补药var bill_type: Int = 0//单据状态 0-未完成 1-已完成 -1--已做废var bill_status: Int = 0//行号var serial_no: String = ""//药品编号var drugs_code: String = ""//HIS药品IDvar drugs_hisid: String? = ""//批号var batch_no: String? = ""//生产厂家var produce_name: String? = ""//生产日期var produce_date: String? = ""//效期var expire_date: String? = ""//单号需取数量var bill_qty: Int = 0//实取数量var real_qty: Int = 0//实取的库存ID信息var stock_id: Long? = -1//创建日期var create_date: String? = DateTimeUtils.getCurrectDate()//创建人var create_by = ""//修改日期var last_update_date: String? = DateTimeUtils.getCurrectDate()//修改人var last_update_by: String? = ""//通讯次数var upload_times: Int? = 0//通讯失败信息var upload_erromsg: String? = ""//上传标志 0-未上传 1-已上传var upload_flag: Int = 0//接口中间表的IDvar interface_id: Long? = 0}
//数据库升级var migration1_2 = object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//创建本地的周转库取药数据表var turnoversql =" CREATE TABLE if not exists t_Bill_TurnOverPick (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, dept_no TEXT NOT NULL, dept_name TEXT NOT NULL, source_dept_no TEXT NOT NULL, source_dept_name TEXT NOT NULL, bill_no TEXT NOT NULL, bill_date TEXT, bill_type INTEGER NOT NULL, bill_status INTEGER NOT NULL, serial_no TEXT NOT NULL, drugs_code TEXT NOT NULL, drugs_hisid TEXT, batch_no TEXT, produce_name TEXT, produce_date TEXT, expire_date TEXT, bill_qty INTEGER NOT NULL, real_qty INTEGER NOT NULL, stock_id INTEGER, create_date TEXT, create_by TEXT NOT NULL, last_update_date TEXT, last_update_by TEXT, upload_times INTEGER, upload_erromsg TEXT, upload_flag INTEGER NOT NULL, interface_id INTEGER) "database.execSQL(turnoversql)turnoversql =" CREATE INDEX index_t_Bill_TurnOverPick_dept_no ON t_Bill_TurnOverPick (dept_no) "database.execSQL(turnoversql)turnoversql =" CREATE INDEX index_t_Bill_TurnOverPick_drugs_code ON t_Bill_TurnOverPick (drugs_code) "database.execSQL(turnoversql)turnoversql =" CREATE INDEX index_t_Bill_TurnOverPick_bill_date ON t_Bill_TurnOverPick (bill_date) "database.execSQL(turnoversql)turnoversql =" CREATE INDEX index_t_Bill_TurnOverPick_bill_no ON t_Bill_TurnOverPick (bill_no) "database.execSQL(turnoversql)turnoversql =" CREATE INDEX index_t_Bill_TurnOverPick_upload_flag ON t_Bill_TurnOverPick (upload_flag) "database.execSQL(turnoversql)}}
只有表中字段类型都和类中全部一致,运行时才会正常升级,否则会抛出异常
02
修改原表中的主键
package ryb.medicine.database.bean.table;import androidx.room.Entity;import androidx.room.PrimaryKey;import org.jetbrains.annotations.NotNull;import ryb.medicine.library_common.base.DateTimeUtils;/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:9:57* 功能模块说明:*/@Entity(tableName = "t_Dev_Cfg")public class CDev {public CDev() {ipadr = "192.168.0.252";port = 6020;dev_serialno = 1;tagnum = 35;start_tagid = "0001";end_tagid = "0035";grid_cfg = "555|5555";flag = 1;create_date = DateTimeUtils.getCurrectDate();create_by ="";last_update_date = DateTimeUtils.getCurrectDate();last_update_by = "";upload_flag = 0;}//IP地址@NotNullpublic String ipadr;//端口号public int port;//主键//柜子序号@PrimaryKey@NotNullpublic int dev_serialno;//标签个数public int tagnum;//起始标签public String start_tagid;//结束标签public String end_tagid;//货格字符 555|5555 其中|代表上下门分隔,每一行数字代表每行中的多少格public String grid_cfg;//启用标志 0-禁用 1-启用public int flag;//创建日期public String create_date;//创建人public String create_by;//修改日期public String last_update_date;//修改人public String last_update_by;//上传标志 0-未上传 1-已上传public int upload_flag;}
类中结构改了后,接下来就是写迁移的语句,SQLite中没有支持ALTER TABLE DROP相关的语句,所以直接删除表中主键再重新创建主键是不允许的,只能通过重新创建表还实现。因为原表中已经有数据了,为了保证数据库迁移时数据不会导致数据丢失,所以需要将原来的数据先备份到临时表中,然后删除原来的表,再重新创建,接下来将临时表中的数据再插入回来,最后再将临时表删除即可。
var migration2_3 = object : Migration(2, 3) {override fun migrate(database: SupportSQLiteDatabase) {//备份设备表var sql = " CREATE TABLE if not exists tmp_t_Dev_Cfg as select * from t_Dev_Cfg"database.execSQL(sql)sql = " Drop Table if exists t_Dev_Cfg "database.execSQL(sql)//重新创建表sql =" CREATE TABLE t_Dev_Cfg (ipadr TEXT NOT NULL, port INTEGER NOT NULL, dev_serialno INTEGER NOT NULL, tagnum INTEGER NOT NULL, start_tagid TEXT, end_tagid TEXT, grid_cfg TEXT, flag INTEGER NOT NULL, create_date TEXT, create_by TEXT, last_update_date TEXT, last_update_by TEXT, upload_flag INTEGER NOT NULL, PRIMARY KEY(dev_serialno)) "database.execSQL(sql)//将源数据插回表新表中sql =" insert into t_Dev_Cfg(ipadr,port,dev_serialno,tagnum,start_tagid,end_tagid,grid_cfg,flag,create_date,create_by,last_update_date,last_update_by,upload_flag) " +" select ipadr,port,dev_serialno,tagnum,start_tagid,end_tagid,grid_cfg,flag,create_date,create_by,last_update_date,last_update_by,upload_flag from tmp_t_Dev_Cfg"database.execSQL(sql)//删除创建的临时表sql = " Drop Table if exists tmp_t_Dev_Cfg"database.execSQL(sql)}}
03
增加新的视图
package ryb.medicine.database.bean.dataimport androidx.room.Embeddedimport androidx.room.Relationimport ryb.medicine.database.bean.table.CDrugsimport ryb.medicine.database.bean.table.CDrugsStock/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:10:36* 功能模块说明:*/data class DDrugswithStock(@Embedded val drugs: CDrugs,@Relation(parentColumn = "drugs_id",entityColumn = "drugs_id")val stocks: List<CDrugsStock>)
package ryb.medicine.database.bean.viewimport androidx.room.DatabaseView/*** 作者:Vaccae* 邮箱:3657447@qq.com* 创建时间:18:04* 功能模块说明:*/@DatabaseView("select bill_type,id from t_Bill_Pick")data class VTest(//业务类型 0-取药 1-补药 2-盘点 3-周转柜取药var bill_type: Int,//业务ID 每个业务对应的IDvar id: Long)
/*** 注:如果是视图增加视图中前后必须加上`视图名`,否则升级失败。*/var migration3_4 = object : Migration(3, 4) {override fun migrate(database: SupportSQLiteDatabase) {var sql = " Drop View if exists `VTest`";database.execSQL(sql)//创建视图sql ="CREATE View if not exists `VTest` AS select bill_type,id from t_Bill_Pick"database.execSQL(sql)}}
04
执行数据库升级

fun getDatabase(context: Context): AppDataBase {if (INSTANCE == null) {synchronized(lock = AppDataBase::class) {if (INSTANCE == null) {INSTANCE = Room.databaseBuilder(context.applicationContext,AppDataBase::class.java, DATABASE_NAME).allowMainThreadQueries()//允许在主线程查询数据.addMigrations(migration1_2, migration2_3, migration3_4)//数据库升级时执行//使用fallback下面这句,当数据库执行失败时会直接清空数据库重建//.fallbackToDestructiveMigration().build()}}}return INSTANCE!!}

完
扫描二维码
获取更多精彩
微卡智享

「 往期文章 」
文章转载自微卡智享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。






