简体   繁体   中英

Room is not updating schema of the database

I have the following table:

@JsonClass(generateAdapter = true)
@Entity(tableName = "lexeme")
data class Lexeme(
    @PrimaryKey
    @ColumnInfo(typeAffinity = ColumnInfo.INTEGER)
    val id: Long,
    val form: String,
    val formNoAccent: String,
    val formUtf8General: String,
    val reverse: String,
    val number: Int?,
    val description: String?,
    val noAccent: String?,
    val consistentAccent: String?,
    val frequency: String?,
    val hyphenations: String?,
    val pronunciations: String?,
    val stopWord: String?,
    val compound: String?,
    val modelType: String?,
    val modelNumber: String?,
    val restriction: String?,
    val staleParadigm: String?,
    val notes: String?,
    val hasApheresis: String?,
    val hasApocope: String?,
    val createDate: String?,
    val modDate: String?
)

Whatever I am trying to do, id , form , formNoAccent and formUtf8General are not set as Not Null and the id is not set as affinity = 3 , I have tried both Int and Long.

I am trying to preload a database into my app but I am getting the following error:

     Expected:
    TableInfo{name='lexeme', columns={hyphenations=Column{name='hyphenations', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, staleParadigm=Column{name='staleParadigm', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, modDate=Column{name='modDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, notes=Column{name='notes', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, hasApheresis=Column{name='hasApheresis', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, description=Column{name='description', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, consistentAccent=Column{name='consistentAccent', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, formNoAccent=Column{name='formNoAccent', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, noAccent=Column{name='noAccent', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, modelType=Column{name='modelType', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, reverse=Column{name='reverse', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, compound=Column{name='compound', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, hasApocope=Column{name='hasApocope', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, frequency=Column{name='frequency', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, number=Column{name='number', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, formUtf8General=Column{name='formUtf8General', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, form=Column{name='form', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, restriction=Column{name='restriction', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, modelNumber=Column{name='modelNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, stopWord=Column{name='stopWord', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, pronunciations=Column{name='pronunciations', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, createDate=Column{name='createDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
     Found:
TableInfo{name='lexeme', columns={hyphenations=Column{name='hyphenations', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, staleParadigm=Column{name='staleParadigm', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, modDate=Column{name='modDate', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, notes=Column{name='notes', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, hasApheresis=Column{name='hasApheresis', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, description=Column{name='description', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, consistentAccent=Column{name='consistentAccent', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, formNoAccent=Column{name='formNoAccent', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, noAccent=Column{name='noAccent', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, modelType=Column{name='modelType', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, reverse=Column{name='reverse', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, compound=Column{name='compound', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, hasApocope=Column{name='hasApocope', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, frequency=Column{name='frequency', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, number=Column{name='number', type='integer', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, formUtf8General=Column{name='formUtf8General', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, form=Column{name='form', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, restriction=Column{name='restriction', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, modelNumber=Column{name='modelNumber', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, stopWord=Column{name='stopWord', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, pronunciations=Column{name='pronunciations', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, createDate=Column{name='createDate', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}

The simplest way to ensure that found matches expected is to use the SQL that Room generates to create the tables in the tool in which you are using to create the pre-packaged database.

The SQL can be found by compiling the project after creating all the entities and adding them in the list of entities in the class that is annotated with @Database.

After compiling look at the java (generated) and find the class that is the same name as the class that is annotated with @Database suffixed with _Impl . Inside the class there will be a method called createAllTables this has the SQL for all the tables, views, indexes and for FTS tables the triggers that room expects.

Fix

You have to ensure that the tables in the pre-packaged database (the found ) match those in the SQL ( the expected ).

Assuming that you have spotted all the differences then you could try changing the Lexeme class to be:-

@JsonClass(generateAdapter = true)
@Entity(tableName = "lexeme")
data class Lexeme(
    @PrimaryKey
    //@ColumnInfo(typeAffinity = ColumnInfo.INTEGER) //<<<<< effectively removed 
    val id: String, //<<<<< changed to be TEXT
    val form: String,
    val formNoAccent: String?, //<<<<< changes to be NOT NULL 
    val formUtf8General: String?, //<<<<< changes to be NOT NULL
    val reverse: String,
    val number: Int?,
    val description: String?,
    val noAccent: String?,
    val consistentAccent: String?,
    val frequency: String?,
    val hyphenations: String?,
    val pronunciations: String?,
    val stopWord: String?,
    val compound: String?,
    val modelType: String?,
    val modelNumber: String?,
    val restriction: String?,
    val staleParadigm: String?,
    val notes: String?,
    val hasApheresis: String?,
    val hasApocope: String?,
    val createDate: String?,
    val modDate: String?
)
  • note I haven't tried the above
  • you may have to make other changes to suit, pay special attention to the id column as the id will not be generated as may have been expected.
  • I personally do not recommend trying to match the Entity (the Expected ) to an existing table ( the Found ). So I would suggest considering the following to adjust the pre-packaged database to suit the Entity:-

If you have a lot of data in the pre-packaged database then what you could do is use SQL to (if you have no or little data then just drop the lexeme table and create as per step 2):-

  1. Rename the lexeme table eg

    ALTER TABLE lexeme RENAME TO lexeme_old;

  2. Create the lexeme using the SQL for the lexeme table as copied from the generated java.

  3. Copy the data from the lexeme_old table to the lexeme table eg

    INSERT INTO lexeme (SELECT * FROM lexeme_old);

  4. DROP the lexeme_old table using DROP TABLE IF EXISTS lexeme_old

  5. Optionally use the SQL VACUUM;

  6. Close the database, exit the tool, start the tool, open/connect the database check that the changes have been applied, close the database then copy the pre-packaged database to the app.

  • note that as the id column is TEXT then if any of the values are not valid integers then you will get an SQLITE_MISMATCH error.

If you do get the SQLITE_MISMATCH then you can do one of the following:-

  1. Change the id column from val id: Long to val id: String AND remove the line @ColumnInfo(typeAffinity = ColumnInfo.INTEGER) .
  2. change the SQL used in step 3 to be

:-

INSERT INTO lexeme (`form`,`formNoAccent`,`formUtf8General`,`reverse`,`number`,`description`,`noAccent`,`consistentAccent`,`frequency`,`hyphenations`,`pronunciations`,`stopWord`,`compound`,`modelType`,`modelNumber`,`restriction`,`staleParadigm`,`notes`,`hasApheresis`,`hasApocope`.`createDate`,`modDate`) SELECT `form`,`formNoAccent`,`formUtf8General`,`reverse`,`number`,`description`,`noAccent`,`consistentAccent`,`frequency`,`hyphenations`,`pronunciations`,`stopWord`,`compound`,`modelType`,`modelNumber`,`restriction`,`staleParadigm`,`notes`,`hasApheresis`,`hasApocope`.`createDate`,`modDate` FROM lexeme_old;
  • note the SQL has not been checked, consider it as in-principle.

The above steps could be undertaken in whatever tool you are using/did use to create the pre-packaged database.

Another option would be to make the changes on the fly using the prePackagedDarabaseCallback . This is an example of using the callback that actually does the steps above with just a few changes. However, it is written in java and it also requires at least Room version 2.4.0-beta02 (suggest using 2.4.0 as it's now been released).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM