Roomのデータ移行ピット

6262 ワード

最近Roomを使用してバージョンアップを行い、テーブルからフィールドを削除します.新しいフィールドを追加する方法はすでに使用されています.
val goodsDatabase = Room.databaseBuilder(
                            context.applicationContext, 
                            GoodsDatabase::class.java, 
                            "goods")
                .allowMainThreadQueries()
                .addMigrations(object : Migration(2, 3) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL("ALTER TABLE stock_goods ADD goods_discount INTEGER NOT NULL DEFAULT 100")
                })
                .build()

簡単です.migrationではsql文でstock_にgoodsこの表にIntegerタイプのgoodsが追加されましたMigration(2,3)の2と3が現在のデータベースのバージョンとアップグレードされたデータベースのバージョンであるdiscountフィールド.
そして、削除フィールドは新規フィールドと同様に、sql文を「ALTER TABLE stock_goods DROP COLUMN goods_model」に変更すればよいと思います(goods_modelは新規フィールドです).結果は直接エラーを提示し、ネットで調べてみると元のroomはデータベースのフィールドを直接削除できないことがわかりましたので、別の方法を考えるしかありません.
//                                         
                        database.execSQL(
                            "CREATE TABLE new_stock_goods (goods_barcode TEXT NOT NULL," +
                                    " goods_name TEXT NOT NULL, goods_price REAL NOT NULL, id INTEGER NOT NULL, goods_id TEXT NOT NULL," +
                                    " shop_id INTEGER NOT NULL, count INTEGER NOT NULL, PRIMARY KEY(goods_barcode))"
                        )
//                                     
                        database.execSQL(
                            "INSERT INTO new_stock_goods(goods_barcode, goods_name, goods_price, id, goods_id, shop_id, count) " +
                                    "SELECT goods_barcode, goods_name, goods_price, id, goods_id, shop_id, count FROM stockgoods"
                        )
//                            
                        database.execSQL("DROP TABLE IF EXISTS stockgoods")
//                                  
                        database.execSQL("ALTER TABLE new_stock_goods RENAME TO stockgoods")

これは私がネットブログを参考にして得た新しい方法で、直接削除できない以上、新しいテーブルを作るしかありません.
まず新しいテーブルをnewと名付けましたstock_goods、それから各種のフィールドを定義して、フィールドの名前は古いテーブルと一致して、ただ古いテーブルの要らないgoods_モデルは定義しないでください.
古いテーブルのデータを新しいテーブルにコピーしgoods_モデルのデータはコピーする必要はありません.
コピーが終わったら古いテーブルを削除し、最後に新しい名前を古いテーブルのstockに変更します.goods、これで完成です.
総じて言えばやはり面倒で、私は今表の中のフィールドは7、8つしかなくて、一つ一つ書くのは少し面倒で、もし更に増加するならば、更に1種の苦しみで、もっと良い移転方法があるかどうか分からないで、もし大神が知っているならば、教えてほしいです.
また、roomデータの移行をテストするときに遭遇したピットについて説明します.
私は上に新しいテーブルを作成したsql文で、各フィールドの後ろにNOT NULLという文を追加しました.これはデータベースフィールドの属性に対する宣言です.データベースの各columnにはnotNullという属性があり、フィールドにNOT NULLという文を付けると、対応するnotNullはtrueに等しくなります.追加しない場合、roomは@Entity注記でデフォルトで作成するテーブルの各フィールドのnotNullがtrueであるため、新しいテーブルを作成するフィールドの後ろにNOT NULLを追加しない場合、そのnotNullがfalseであるjavaが現れる.lang.IllegalStateException:Migration didn't properly handle StockGoodsのエラー.
今私は
database.execSQL(
                            "CREATE TABLE new_stock_goods (goods_barcode TEXT NOT NULL," +
                                    " goods_name TEXT NOT NULL, goods_price REAL NOT NULL, id INTEGER NOT NULL, goods_id TEXT NOT NULL," +
                                    " shop_id INTEGER NOT NULL, count INTEGER NOT NULL, PRIMARY KEY(goods_barcode))"
                        )

でgoods_barcodeの後ろのNOT NULLを外してから実行するとエラーが発生します
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hongyue.shopsystem/com.hongyue.shopsystem.ui.stock.activity.StockActivity}: java.lang.IllegalStateException: Migration didn't properly handle StockGoods(com.hongyue.shopsystem.mvp.model.bean.StockGoods).
     Expected:
    TableInfo{name='StockGoods', columns={goods_id=Column{name='goods_id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, goods_name=Column{name='goods_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, count=Column{name='count', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, shop_id=Column{name='shop_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_price=Column{name='goods_price', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}
     Found:
    TableInfo{name='StockGoods', columns={goods_id=Column{name='goods_id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, count=Column{name='count', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_name=Column{name='goods_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, shop_id=Column{name='shop_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=1}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_price=Column{name='goods_price', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=null}

このエラーは、新しいテーブルと@Entity注記のクラスに対応するデータテーブルのフォーマットが異なるため、上記のエラー情報と比較して、このような違いを見つけることができます.

     Expected:
    goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1}
     Found:
    goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=1}

その他の属性はすべて同じで、notNullだけが異なって、これも間違いの原因をもたらすので、javaが更に現れるならば.lang.IllegalStateException:Migration didn't properly handleのエラーですが、エラー情報をよく比較して、何が原因なのかを見て、対応するプロパティを同じように修正すればいいのです.