I have an app which makes a database by Room. Then I move the database to the server to populated. While updating or initializing the app, the populated database is downloaded by the app. But when I want to use it by Room I get an error message:
A migration from 2 to 1 is necessary. Please provide a Migration in
the builder or call fallbackToDestructiveMigration in the builder in
which case Room will re-create all of the tables.
I cleaned whole build folder then I did all again. But I get the same error again!
Where I get error is:
String SALE_DATABASE_NAME = "SaleDatabase.db";
SaleDatabase saleDatabase = Room.databaseBuilder(this,
SaleDatabase.class, SALE_DATABASE_NAME)
//.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.build();
saleDatabase.getPathDao().getPaths(); //Getting error
Database class:
#Database(entities = {OrderEntity.class, OrderDetailEntity.class
, CardIndexDetailEntity.class, CardIndexEntity.class
, CategoryEntity.class, CodingEntity.class
, CustomerBasicEntity.class, CustomerBuyEntity.class
, CustomerChequeEntity.class, CustomerCreditEntity.class
, PathEntity.class, UnvisitedCustomerReasonEntity.class
, ProfileCategoryEntity.class, SubCategoryDetailEntity.class
, SubCategoryEntity.class, ReasonEntity.class}, version = 1)
public abstract class SaleDatabase extends RoomDatabase{
public abstract PathDao getPathDao();
#Override
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
return null;
}
#Override
protected InvalidationTracker createInvalidationTracker() {
return null;
}
}
My hash code in both database and SaleDatabase_Impl.java class is same.
So my questions are:
Why does it say migration 2 to 1 as a downgraded job?
How can I ignore version until application built completely
Is there a way to clean and reset room if I update my version to 2?
I solved this way:
Clear app data
In the manifest set android:allowBackup="false"
Related
I am writing units tests for an app's Room database. Here is relevant code when using Room.databaseBuilder()
#Before
public void createDb() {
Context context = ApplicationProvider.getApplicationContext();
db = Room.databaseBuilder(context, AppDatabase.class, "AppDatabase").build();
itemDao = db.itemDao();
}
The test fails here and the error is android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: item.id (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY[1555]). (I think I know what causes the error, I need I don't have an auto generated primary key for entries so a record is inserted with an id already in the table. Anyway, that's not what my question is.)
And same method, using Room.inMemoryDatabaseBuilder(). Here the test passes.
#Before
void createDb() {
Context context = ApplicationProvider.getApplicationContext();
db = Room.inMemoryDatabaseBuilder(context, AppDatabase.class).build();
itemDao = db.itemDao();
}
And the test itself is:
#Test
public void writeItemAndReadInList() {
float value = 3.0f;
Item item = new Item(value, new Date());
itemDao.insert(item);
List<Item> all = itemDao.getAll();
assertEquals(all.get(0).getValue(), value);
}
So the question is why does the first method fail and the second one pass? What difference is that one database is created in memory and the other not? If the problem is with inserting with unique primary keys, shouldn't it be present in both methods? Unless that is not the problem here.
Room.databaseBuilder(..).build() won't drop your database between runs, it is persistent. Room.inMemoryDatabaseBuilder(...).build() it is not (all data is lost when the process is killed), that's why you're not getting unique constraint exceptions when you first run the test.
Fairly new to room and having a hard time finding info on this. Currently we define our database like this:
#Database(entities = {TwcLocation.class,
CurrentObservation.class,
Day.class,
Hour.class,
Station.class,
StationCurrentObservation.class}, version = 1, exportSchema = false)
public abstract class TwcLocationDatabase extends RoomDatabase {
Now, we want to remove a bunch of unused entities so it looks like this:
#Database(entities = {TwcLocation.class, Tag.class}, version = 1)
#TypeConverters({TwcLocationTypeConverter.class})
public abstract class NbcRoomDatabase extends RoomDatabase {
Question: How do I do this migration?
You need to increment the version (so it will become version = 2).
Next, when building the Room instance by using the Room.databaseBuilder method, add the addMigration() line.
As migration, pass it the following to remove the tables:
// Migration from version 1 to 2
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
#Override
public void migrate(SupportSQLiteDatabase database) {
// Remove the table
database.execSQL("DROP TABLE day"); // This line for each table that you want to remove
}
};
Later on you might need multiple different migrations, you can do so by using the addMigrations() method:
Room.databaseBuilder(..., ..., ...)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build()
Other option is to use fallbackToDestructiveMigration and increment database version. In such case you will not have to provide migrations. However it will clear data in all old tables.
So basically i am using room and trying to add migration from database version 1 to 2 but my alter command is not working
My current implementation is below :
void init() {
db = Room.databaseBuilder(Global.getInstance(),
AppDatabase.class, "feed").addMigrations(MIGRATION_1_2).build();
}
Migration property :
static final Migration MIGRATION_1_2 = new Migration(1,2) {
#Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'post' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0");
Log.d("VROM","Migration");
}
};
Database implementation :
#Database(entities = {Feed.class, DownloadModel.class}, version = 1) public abstract class AppDatabase extends RoomDatabase {
public abstract DaoAccess getFeedDao();}
So after incrementing the version from 1 to 2, the execSQL() is executed but new column is not added in my db.
I have pulled my db from app directory and checked multiple times but column is not there. Apart from that if I kill my app and launch it again the migrate method is called again , don't know if this is the intended functionality but it breaks the functionality for me.I thought migrate will be only called once same as onUpgrade()
Make sure your column is in model class. In your case, you are adding column age like this: ADD COLUMN 'age' INTEGER, so you must have int age in your model class.
Also, it is a good idea to write migration test to known exactly what is failing. You can find about migration test in android documentation here: https://developer.android.com/topic/libraries/architecture/room.html#db-migration-testing
Try Changing version=2 in AppDatabase inside #Database.
I need some help with Realm.io, I've just been presented to it in a project I'm joining. The former developer showed the source code of our app recently and told me he is using Realm.io just to check if it's the first time the app has been opened by the user. Here is a code snippet of what he is using to do that on the onCreate() method. I'm using Android Studio for development.
Realm.init(getApplicationContext());
final Realm realm = Realm.getDefaultInstance();
final RealmResults<Configuracao> configuracoes =
realm.where(Configuracao.class)
.equalTo("chave", "primeiroAcesso")
.findAll();
The problem is that now I need to insert new data on the database so I've created a class that looks like this:
public class medicine extends RealmObject {
#PrimaryKey
private int id;
private String med;
private String doctor;
/* Setters and getters here */
}
I'm running into the RealmMigrationNeeded exception, I read the docs and I'm aware that I need to do the migration.
My question is: Where exactly do I put the migration code? Should I put it in the new class file?
Also, in the documentation they tell me that I need to change the version of the schema through something like this:
RealmConfiguration config1 = new RealmConfiguration.Builder()
.name("default1.realm")
.schemaVersion(3)
.migration(new Migration())
.build();
But they also say that if that version doesn't exist an exception will be thrown so I'm guessing I need to change the schema before doing that?
Do I have to change anything in the database itself and then call the migration inside the app, or the migration is the process to change the schema? Sorry about the long text but I'm really confused. Thanks for the help in advance.
Yes, you need to create a custom Migration class that must implement RealmMigration. The schema version you provide in the configuration is the version your Realm will have after the migration is run. You can see an example here: https://github.com/realm/realm-java/blob/master/examples/migrationExample/src/main/java/io/realm/examples/realmmigrationexample/model/Migration.java
In your case it would look something like this:
public class MyMigration implements RealmMigration {
#Override
public void migrate(final DynamicRealm realm, long oldVersion, long newVersion) {
RealmSchema schema = realm.getSchema();
if (oldVersion == 2) {
schema.create("medicine")
.addField("id", int.class, FieldAttribute.PRIMARY_KEY)
.addField("med", String.class)
.addField("doctor", String.class);
}
}
}
I used Realm in my android untill now with
new RealmConfiguration.Builder(this) .build();
I just read later about the possibility to add schema and migration.
So in my new version for my app i want to add the migration feature.
so i changed the line above to:
new RealmConfiguration.Builder(this) .schemaVersion(0) .migration(new Migration()) .build();
but now I get the error
IllegalArgumentException: Configurations cannot be different if used to open the same file.
How can i change the configuration without deleting the database
I think your problem is that you are creating your RealmConfiguration multiple times. That shouldn't be a problem by itself (although it is inefficient), but the problem arises with your Migration class. Internally we compare all state in the configuration objects and if you didn't override equals and hashCode in your Migration class you have a case where new Migration().equals(new Migration()) == false which will give you the error you are seeing.
One solution is adding this:
public class Migration implements RealmMigration {
// Migration logic...
#Override
public int hashCode() {
return 37;
}
#Override
public boolean equals(Object o) {
return (o instanceof Migration);
}
}
When you set a new schema version with schemaVersion(), the version number should equal to or higher than the schema version of the existing realm file. The RealmMigration() you provide should then be able to convert older version of schemas to the new version.
I'd suggest to check your existing schema version first, then check your RealmObjects for appropreate conversion.