Как удалить объекты Realm, на которые не ссылаются другие объекты во время миграции? - PullRequest
0 голосов
/ 18 марта 2019

У меня две модели -

class Direction : RealmObject {
    var distance : Int
    var polyline : String
}

class Route  : RealmObject {
    var id : String
    var directionList : RealmList<Direction>
}

Я использовал insertOrUpdate() для обновления класса Route, предполагая, что когда я его вызываю, существующие объекты direction в directionList были удалены и заменены новым предоставленным мною списком. Однако недавно я обнаружил, что этого не происходит. Даже каскадное удаление не поддерживается, когда я звоню route.deleteFromRealm(). Итак, теперь я получил сотни объектов в таблице «Направление» без ссылок на них.

Как я могу удалить все объекты из класса Direction, у которых нет объектов Route, ссылающихся на них в миграции Realm?

Ответы [ 3 ]

1 голос
/ 19 марта 2019

Вот как я это решил -

override fun migrate(realm: DynamicRealm, oldVersion1: Long, newVersion: Long) {

    if (oldVersion == 2L) {

        val routeSchema = schema.get("Route")
        val directionSchema = schema.get("Direction")

        /*
        Creating a new temp field called isLinked which is set to true for those which are
        references by Route objects. Rest of them are set to false. Then removing all
        those which are false and hence duplicate and unnecessary. Then removing the temp field
        isLinked
         */
        directionSchema!!
                .addField("isLinked", Boolean::class.java)
                .transform { obj ->
                    //Setting to false for all by default
                    obj.set("isLinked", false)
                }

        routeSchema!!.transform { obj ->
            obj.getList("directionList").forEach {
                //Setting to true for those which are referenced
                it.set("isLinked", true)
            }
        }

        //Removing all those which are set as false
        realm.where("Direction")
                .equalTo("isLinked", false)
                .findAll()?.deleteAllFromRealm()

        directionSchema.removeField("isLinked")

        //Rest of the migration
    }
}

Есть еще кое-что, что я обнаружил. Согласно этому очень информативному докладу о Realm - https://academy.realm.io/posts/jp-simard-realm-core-database-engine/ (перейдите к 28:45), есть способ удалить все эти не связанные узлы из B-дерева. Однако я не мог найти способ сделать это. Realm.compactRealm() казалось способом сделать это, но это не сработало.

1 голос
/ 19 марта 2019

Два возможных способа, которыми я могу придумать.

Первый может не помочь вам в это время, но возможно в будущем.Добавляя свойство LinkingObjects в класс Direction, вы можете позволить модели определять, какие Direction объекты не имеют связанных Route объектов.LinkingObjects описывается здесь (https://realm.io/docs/java/5.8.0/api/io/realm/annotations/LinkingObjects.html). со свойством Direction: например:

\@LinkingObjects("direction")
final RealmResults<Route> routes = null;

Затем вы можете удалить любые объекты, где:

RealmResults<Direction> unusedDirections = realm.where(Direction.class).isEmpty("routes").findAll();

Возможно, вам понадобитсячтобы сделать это для вашего следующего релиза.

Второй способ более сложен, но по существу:

  1. Найти все Direction объектов: RealmResults<Direction> redundantDirections = realm.where(Direction.class).findAll();
  2. Найти все Route объекты (аналогично приведенным выше).
  3. Выполнить итерацию по всем Route объектам.
  4. Отфильтровать запрос redundantDirections, чтобы исключить любые Direction объекты, на которые ссылается каждый Route объект.
  5. Удалить окончательный redundantDirections.

Я надеюсь, что есть третий способ, о котором я не знаю .....

0 голосов
/ 28 марта 2019

Как я могу удалить все те объекты из класса Direction, у которых нет объектов Route, ссылающихся на них в миграции Realm?

Должно быть легко с помощью DynamicRealmObject.linkingObjects.

val routes = realm.where("Destination").findAll()
routes.createSnapshot().forEach { route ->
    val linkingObjects = route.linkingObjects("Route", "directionList")
    if(linkingObjects.isEmpty()) {
        route.deleteFromRealm()
    }
}

Теоретически это должно работать

...