I have a production app made with Flutter that I started as a side project, now it has couple hundred users and I want to migrate the codebase to Kotlin (yes Im going to rewrite all the code).
The problem I’m facing is with the database, I currently use Sqlite in Flutter and I want to use Room without losing any of the user data.
Is this posible? If not, can I still use the same Sqlite after the user update the new version of the app made with Kotlin?
2
Answers
You can retain all your data with no issues.
Put your database file .db to the assets folder
and build the database like this:
make sure that your model classes representing the entities match the columns and datatypes of your database file
Yes (albeit potentially complex).
Assuming that each existing user(device) has data unique to that user then you can effectively utilise that existing data.
Basically you need to change the App to introduce
@Entity
annotated classes, one per existing table.tableName
parameter of the@Entity
annotation to specify the table name to be utilised.You should then create the
@Database
annotated class with the list of@Entity
annotated classes provided via theentities
parameter of the@Database
annotation.At this stage you should successfully compile the project. The java(generated) directory would then include a subdirectory with a class that is the same name as the
@Database
annotated class but suffixed with _Impl.Within this class there will be a function/method called createAllTables. This will have an
execSQL
statement for creating each table (you can ignore the room_master table), and if any, a statement for the creation of indexes.This SQL is exactly the schema that Room EXPECTS. Room will not accept any difference.
If the definition exactly matches the existing tables then in theory you could continue as such (database version number being the same). However, if there are any differences then you would need to convert(migrate) the tables.
Migration from non-room compliant tables to room-compliant tables could be reached by following the following steps (assuming the number of columns per table remain unchanged)
In the migration/conversion code per table:-
ALTER TABLE the_table RENAME TO the_table_renamed;
_renamed
part could be whatever suits but it is probably best to be consistent.INSERT INTO the_table SELECT * FROM the_table_renamed;
.1.if the columns are not defined in the same order, or if you need to convert data
coalesce
function)DROP TABLE IF EXISTS the_table_renamed;
DROP INDEX IF EXISTS the_index;
You may want to test that the above works before proceeding.
You would very likely have to convert all the functions that access the database INSERTs, UPDATEs, DELETEs and QUERYs. Using either the equivalent convenience methods
@Insert
,@Update
and@Delete
. Noting:-@Update
and@Delete
convenience methods on the @PrimaryKey (required for all Room tables) to identify the row that is to be affected, the methods have the advantage of return an Int the value being the number of affected rows.@Insert
convenience method returns the rowid of the inserted row (not necessarily the PrimaryKey value)@Query("the_respective_sql")
to get around the shortfalls of the convenience methods. e.g. it is impossible to use the convenience@Update
to change the value of the primary key, but this could be done utilising e.g.@Query("UPDATE the_table SET pkey=:newPkey WHERE pkey=:oldPkey")
In regard to Queries and Relationships you typically utilise a POJO (class not annotated with
@Entity
) where a field for the parent is annotated with@Embedded
and the child(ren) field (typically aList<the_respective_@entity_annotated_child_class>)
annotated with@Relation
annotation.