Exception "Primary key property XXX has duplicate values after migration."
See original GitHub issueWhen I started using the migration, I began to receive periodic crash messages from crashlytics like this:
Caused by java.lang.IllegalStateException: Primary key property 'Relation.id' has duplicate values after migration.
at io.realm.internal.OsSharedRealm.nativeGetSharedRealm(OsSharedRealm.java)
at io.realm.internal.OsSharedRealm.<init>(OsSharedRealm.java:171)
at io.realm.internal.OsSharedRealm.getInstance(OsSharedRealm.java:241)
at io.realm.BaseRealm.<init>(BaseRealm.java:136)
at io.realm.BaseRealm.<init>(BaseRealm.java:105)
at io.realm.Realm.<init>(Realm.java:164)
at io.realm.Realm.createInstance(Realm.java:435)
at io.realm.RealmCache.doCreateRealmOrGetFromCache(RealmCache.java:342)
at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:282)
at io.realm.Realm.getInstance(Realm.java:364)
at my.app.package.realm.RealmTemplate.lambda$observeObject$3(RealmTemplate.java:72)
at my.app.package.realm.-$$Lambda$RealmTemplate$Qgzvh8wX0nrAdIuh0uNxSlktAfQ.apply(lambda)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.onNext(FlowableSwitchMap.java:114)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(FlowableObserveOn.java:400)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(FlowableObserveOn.java:176)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.os.HandlerThread.run(HandlerThread.java:61)
But in migration, I do not touch upon the realm object Relation. My migration:
final class Migration implements RealmMigration {
private static final int MIN_DB_VERSION_FOR_MIGRATION = 11;
private static final String CLASS_APP_INSTANCE = "AppInstance";
@Override
public void migrate(@NonNull final DynamicRealm realm, final long originalVersion, final long newVersion) {
Timber.d("Start migration flow from DB v.%s to v.%s", originalVersion, newVersion);
long oldVersion = originalVersion;
if (oldVersion < MIN_DB_VERSION_FOR_MIGRATION) {
final IllegalStateException exception = new IllegalStateException("Migration is unsupported for DB v." + originalVersion);
Timber.w(exception);
throw exception;
} else {
// Access the Realm schema in order to create, modify or delete classes and their fields.
final RealmSchema schema = realm.getSchema();
/*
Migration v.11 -> v.12
class House v.11 -> class House v.12
add-> @Nullable String alert
*/
if (oldVersion == MIN_DB_VERSION_FOR_MIGRATION) {
Timber.d("Migrate DB from v.11 to v.12");
//change schema
schema.get("House").addField("alert", String.class);
// Request missing data from server
final DynamicRealmObject appInstance = realm.where(CLASS_APP_INSTANCE).findFirst();
if (appInstance != null) {
appInstance.set("initialSyncDate", null);
}
oldVersion++;
}
/*
Migration v.12 -> v.13
class AppInstance v.12 -> class AppInstance v.13
String version rename-> String appVersion
String versionCode rename-> String appVersionCode
add-> String osVersion
add-> String osBuild
*/
if (oldVersion == 12) {
Timber.d("Migrate DB from v.12 to v.13");
realm.delete(CLASS_APP_INSTANCE);
//change schema
schema.get(CLASS_APP_INSTANCE)
.renameField("version", "appVersion")
.renameField("versionCode", "appVersionCode")
.addField("osVersion", String.class)
.addField("osBuild", String.class);
oldVersion++;
}
/*
Migration v.13 -> v.14
class PendingFilledField v.13 -> class PendingFilledField v.14
boolean deleted; remove->
class Address v.13 -> class Address v.14
String geoLAT change type-> Double geoLAT
String geoLON change type-> Double geoLON
*/
if (oldVersion == 13) {
Timber.d("Migrate DB from v.13 to v.14");
//change schema
schema.get("PendingFilledField")
.removeField("deleted");
final RealmObjectSchema address = schema.get("Address");
address.addField("geoLAT_tmp", Double.class)
.transform(obj -> {
if (RealmFieldType.STRING == obj.getFieldType("geoLAT")) {
final String oldGeoLAT = obj.getString("geoLAT");
if (oldGeoLAT != null) {
obj.setDouble("geoLAT_tmp", Double.parseDouble(oldGeoLAT));
}
}
})
.removeField("geoLAT")
.renameField("geoLAT_tmp", "geoLAT");
address.addField("geoLON_tmp", Double.class)
.transform(obj -> {
if (RealmFieldType.STRING == obj.getFieldType("geoLON")) {
final String oldGeoLON = obj.getString("geoLON");
if (oldGeoLON != null) {
obj.setDouble("geoLON_tmp", Double.parseDouble(oldGeoLON));
}
}
})
.removeField("geoLON")
.renameField("geoLON_tmp", "geoLON");
oldVersion++;
}
}
}
@Override
public boolean equals(final Object o) {
final boolean result;
if (this == o) {
result = true;
} else {
result = o != null && getClass() == o.getClass();
}
return result;
}
@Override
public int hashCode() {
return 42;
}
}
Relation class:
public class Relation extends RealmObject {
@PrimaryKey
private Long id;
private House house;
@Nullable
private String type;
@Nullable
private String status;
@Nullable
private String fio;
@Nullable
private String relationReason;
}
Version of Realm and tooling
Realm version(s): 5.1.0
Realm sync feature enabled: no
Realm configuration:
new RealmConfiguration
.Builder()
.name(realmName)
.schemaVersion(Constants.DB_VERSION)
.directory(dbDir)
.migration(MIGRATION)
.encryptionKey(key)
.initialData(initTx)
.build()
Android Studio version: 3.1.2
Which Android version and device:
- Lenovo TAB3 730X, android 6.0
- Redmi Note 4, android 7.0
- Redmi 5 Plus, android 7.1.2
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:8 (3 by maintainers)
Top Results From Across the Web
MySQL 1062 - Duplicate entry '0' for key 'PRIMARY'
A PRIMARY KEY is a unique index, so if it contains duplicates, you cannot assign the ... Run the following query in the...
Read more >The attempt to add a row to the data flow task buffer with error ...
After migration and upgrade, a few SSIS packages started throwing errors like The ... Can't insert duplicate key in object Table XXX.
Read more >Cannot Create XML Backup Due to ObjectNotFoundException ...
In this case, you can check the first line and see that the row has a primary key of 5. Each property is...
Read more >SQLSTATE[23000]: Integrity constraint violation: 1062 ... - Drupal
PDOException : SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '' for key 2: INSERT INTO {file_managed} (filesize, ...
Read more >Removing Duplicate Items from a Mailbox | EighTwOne (821)
For those involved with Exchange migration projects or managing ... Note that PidTagSearchKey will have duplicate values for copied objects.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I have “solved” my issue by ensuring that
ids
were sane by the end of the migration. Since I never depend on theids
for ordering nor I store them directly as a property in other tables, I didn’t have any other considerations. I’m not sure if this has any side effects on the relations between objects, but my main focus was on stopping the constant crashes.Just had this same issue on version 5.0.1 after a migration. The only change that was made to the schema was:
Here are the crash logs which are not at all related to the field that I’ve added:
Caused by java.lang.IllegalStateException: Primary key property 'CartAttributes.name' has duplicate values after migration. at io.realm.internal.OsSharedRealm.nativeGetSharedRealm(OsSharedRealm.java) at io.realm.internal.OsSharedRealm.<init>(OsSharedRealm.java:171) at io.realm.internal.OsSharedRealm.getInstance(OsSharedRealm.java:241) at io.realm.BaseRealm.<init>(BaseRealm.java:134) at io.realm.BaseRealm.<init>(BaseRealm.java:103) at io.realm.Realm.<init>(Realm.java:161) at io.realm.Realm.createInstance(Realm.java:446) at io.realm.RealmCache.doCreateRealmOrGetFromCache(RealmCache.java:342) at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:282) at io.realm.Realm.getInstance(Realm.java:375)