Reputation: 2876
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=[]}
Upvotes: 1
Views: 152
Reputation: 56938
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?, //<<<<< changes to be NOT NULL
val formNoAccent: String?, //<<<<< changes to be NOT NULL
val formUtf8General: String?, //<<<<< changes to be NOT NULL
val reverse: String, //<<<<< changes to be NOT NULL (not found by yourself)
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?
)
The SQL generated after the above changes are made is :-
CREATE TABLE IF NOT EXISTS `lexeme` (
`id` TEXT NOT NULL,
`form` TEXT,
`formNoAccent` TEXT,
`formUtf8General` TEXT,
`reverse` TEXT NOT NULL, /* <<<<< ANOTHER MISMATCH SPOTTED */
`number` INTEGER,
`description` TEXT,
`noAccent` TEXT,
`consistentAccent` TEXT,
`frequency` TEXT,
`hyphenations` TEXT,
`pronunciations` TEXT,
`stopWord` TEXT,
`compound` TEXT,
`modelType` TEXT,
`modelNumber` TEXT,
`restriction` TEXT,
`staleParadigm` TEXT,
`notes` TEXT,
`hasApheresis` TEXT,
`hasApocope` TEXT,
`createDate` TEXT,
`modDate` TEXT,
PRIMARY KEY(`id`)
)
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):-
Rename the lexeme table e.g.
ALTER TABLE lexeme RENAME TO lexeme_old;
Create the lexeme using the SQL for the lexeme table as copied from the generated java.
Copy the data from the lexeme_old table to the lexeme table e.g.
INSERT INTO lexeme (SELECT * FROM lexeme_old);
DROP the lexeme_old table using DROP TABLE IF EXISTS lexeme_old
Optionally use the SQL VACUUM;
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.
note the above assumes that there are no other entities/tables or triggers which could complicate matters (especially if the Lexeme tables is a parent to other tables).
note, the above is not necessarily, efficient (if you look at the example linked below it drops indexes, triggers and views and doesn't create them until the data has been copied)
If you do get the SQLITE_MISMATCH then you can do one of the following:-
val id: Long
to val id: String
AND remove the line @ColumnInfo(typeAffinity = ColumnInfo.INTEGER)
.:-
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
;
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).
Upvotes: 1