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.
Related
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"
ok. so i delete my app completely from android. Then on a fresh install i get the error
Field already exists in 'PortfolioCoin': color.
Why is realm trying to migrate on a fresh install?
I got this in my application file
Realm.init(this);
RealmConfiguration configuration = new RealmConfiguration.Builder()
.name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(1)
.migration(new Migration())
//.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(configuration);
Realm.compactRealm(configuration);
and this is my migration file
public class Migration implements RealmMigration {
#Override
public void migrate(final DynamicRealm realm, long oldVersion, long newVersion) {
// During a migration, a DynamicRealm is exposed. A DynamicRealm is an untyped variant of a normal Realm, but
// with the same object creation and query capabilities.
// A DynamicRealm uses Strings instead of Class references because the Classes might not even exist or have been
// renamed.
// Access the Realm schema in order to create, modify or delete classes and their fields.
RealmSchema schema = realm.getSchema();
if (oldVersion == 0) {
RealmObjectSchema portfolioCoinSchema = schema.get("PortfolioCoin");
portfolioCoinSchema
.addField("color", int.class)
.addField("totalValueBTC", double.class);
oldVersion++;
}
}
}
It happens because you're doing a fresh install, which already have the fields "color" and "totalValueBTC", and then you're trying to do a migration from 'oldVersion == 0', which is the default value.
So you're trying to add fields that already exist.
You should either check for a different version code, or you should use the "hasField(field)" method to check if it's already there, before trying to add it via a migration.
I'm working with the default realm instance, which contains some schemas. Now, I want to create a new schema in a different realm instance. So I have created a new Realm configuration, and when I query or store entities for this new schema, I use the new configuration, instead of the default one. In this way, I expect to avoid the neeed of create a migration for the new schema, due to I use it with a different database. But when I use the default realm instance, an exception is thrown (RealmMigrationNeededException), which tells me that I have to create a migration for my new schema. Can I avoid that in any way if I want to work with my new schema only in a new database?
Check Realm's document:
https://realm.io/docs/java/latest/#schemas
You need to define your 2 custom modules for different configurations.
For example, configB only cares about Cat.class schema.
// Create my module A
#RealmModule(classes = { Person.class, Dog.class })
public class MyModule {
}
// Create the module B
#RealmModule(classes = { Cat.class })
public class MyOtherModule {
}
// Set the module in the RealmConfiguration to allow only classes defined by the module.
RealmConfiguration configA = new RealmConfiguration.Builder()
.modules(new MyModule())
.name("A.realm")
.build();
RealmConfiguration configB = new RealmConfiguration.Builder()
.modules(new MyOtherModule())
.name("B.realm")
.build();
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'm new to Realm. I'm using realm as a local db, and if the app is updated i don't want to lose data. What i did earlier is
public static Realm getRealmInstanse(){
RealmConfiguration config = new RealmConfiguration
.Builder()
.deleteRealmIfMigrationNeeded()
.build();
try {
return Realm.getInstance(config);
} catch (RealmMigrationNeededException e){
try {
Realm.deleteRealm(config);
//Realm file has been deleted.
return Realm.getInstance(config);
} catch (Exception ex){
throw ex;
//No Realm file to remove.
}
}
}
Now i think i should do the following:
public static Realm getRealmInstanse(){
RealmConfiguration config = new RealmConfiguration
.Builder()
.migration(new RealmMigration() {
#Override
public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
}
})
.build();
return Realm.getInstance(config);
}
What should i do inside migrate() method in order to copy the data? And what about schema, should i uses schema version and for what purposes?
And what is the logic of changing the schema? For example, if for some reason i will change the structure of the db, can i just change the schema inside migrate() method?
I've found this example but i don't know actually if it is saving data or just changing the schema
if (oldVersion == 0) {
RealmObjectSchema personSchema = schema.get("Person");
// Combine 'firstName' and 'lastName' in a new field called 'fullName'
personSchema
.addField("fullName", String.class, FieldAttribute.REQUIRED)
.transform(new RealmObjectSchema.Function() {
#Override
public void apply(DynamicRealmObject obj) {
obj.set("fullName", obj.getString("firstName") + " " + obj.getString("lastName"));
}
})
.removeField("firstName")
.removeField("lastName");
oldVersion++;
}
What should i do inside migrate() method in order to copy the data?
Nothing, data is automatically kept between app updates (provided you have not changed the schema while also doing deleteRealmIfMigrationNeeded()).
If you change the database schema and have set deleteRealmIfMigrationNeeded(), the data will be deleted in order to migrate to the new schema automatically.
If you change the database schema and have not set deleteRealmIfMigrationNeeded(), you must provide a RealmMigration, or the app will crash with a "migration needed" exception.
For example, if for some reason i will change the structure of the db, can i just change the schema inside migrate() method?
Yes. You can interact with the DynamicRealm that is passed to #Override public void migrate() to specify the changes required to migrate to a new schema version.
You should give Realm's migration documentation a read.
Sidenote: building the RealmConfiguration as you are doing in your code should not be done every time you request an instance. Rather, do it once, preferably in your Application class. Also see configuring a realm.