【问题标题】:How do I delete Realm objects which are not referenced by any other object during migration?如何在迁移期间删除未被任何其他对象引用的 Realm 对象?
【发布时间】:2019-03-18 12:25:30
【问题描述】:

我有两个模型 -

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

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

我一直在使用insertOrUpdate() 来更新 Route 类,假设当我调用它时,directionList 中的现有方向对象已被删除并替换为我提供的新列表。然而,我最近发现这并没有发生。当我调用route.deleteFromRealm() 时,甚至不支持级联删除。所以现在我在 Direction 表中有数百个对象,没有对象引用它们。

如何从 Direction 类中删除所有在 Realm 迁移中没有引用它们的 Route 对象的对象?

【问题讨论】:

    标签: android realm realm-java


    【解决方案1】:

    我能想到的两种可能的方法。

    第一个现在可能对您没有帮助,但将来可能会。通过将 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&lt;Direction&gt; redundantDirections = realm.where(Direction.class).findAll();
    2. 查找所有Route 对象(类似于上面)。
    3. 遍历所有 Route 对象。
    4. 过滤redundantDirections 查询以排除每个Route 对象引用的任何Direction 对象。
    5. 删除最后的redundantDirections

    我希望有第三种我不知道的方式.....

    【讨论】:

    • 嘿@chris-shaw,感谢您的回答。我有一个后续怀疑。有没有办法在迁移本身中添加这些链接对象?如果有,也许我可以先添加它,然后删除未链接的那些。但是,除了这个用例之外,我对 linkingObjects 没有任何其他需要,而且对于我的用例来说似乎是多余的。我以某种粗略但有效的方式解决了我的问题,有点类似于你在第二种方式中提到的方式。
    • @abhiank 我不知道。如果有人知道,您可以尝试专门询问其他问题。
    • DynamicRealmObject 实际上有一个linkingObjects 方法,这也让我感到惊讶。
    【解决方案2】:

    这就是我解决它的方法 -

    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() 似乎是一种方法,但它不起作用。

    【讨论】:

      【解决方案3】:

      如何从 Direction 类中删除所有在 Realm 迁移中没有引用它们的 Route 对象的对象?

      应该很容易使用DynamicRealmObject.linkingObjects

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

      理论上应该可行

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多