2016-05-02 11 views
4

Ich habe die Suche nach "Kaskade löschen" -Operation für das Reich. Leider wurde diese Funktion noch nicht implementiert. Ich habe meine eigene Implementierung davon gemacht und es hier geteilt.Realm "Kaskade löschen" auf Android

Wie generischer Code für den Realm "Kaskadenlösch" Vorgang zu machen?

+1

Stack-Überlauf ist für die Programmierung von Fragen. Was ist deine Frage? – CommonsWare

+0

Lassen Sie mich es beenden ... Ich veröffentliche es. –

Antwort

2

1) Kopieren Sie diesen Code in Ihrem Projekt

import android.util.Log; 


import java.lang.reflect.Method; 
import io.realm.RealmList; 
import io.realm.RealmObject; 
import com.company.project.models.IRealmCascade; 

/** 
*/ 

public class RealmUtils 
{ 
public static void deleteCascade(RealmObject dataObject) 
{ 
    if (dataObject == null) 
    { 
     return; 
    } 
    if(IRealmCascade.class.isAssignableFrom(dataObject.getClass())) 
    { 
     for(Method method : dataObject.getClass().getSuperclass().getDeclaredMethods()) 
     { 
      try { 
       //Ignore generated methods 
       if((method.getName().contains("realmGet$")) || (method.getName().contains("access$super"))) 
       { 
        continue; 
       } 
       Class<?> resultType = method.getReturnType(); 
       //Ignore non object members 
       if (resultType.isPrimitive()) { 
        continue; 
       } 

       if (RealmObject.class.isAssignableFrom(resultType)) { 
        //Delete Realm object 
        try { 
         RealmObject childObject = (RealmObject) method.invoke(dataObject); 
         RealmUtils.deleteCascade(childObject); 
        } catch (Exception ex) { 
         Log.e("REALM", "CASCADE DELETE OBJECT: " + ex.toString()); 
        } 
       } else if (RealmList.class.isAssignableFrom(resultType)) { 
        //Delete RealmList items 
        try { 
         RealmList childList = (RealmList) method.invoke(dataObject); 
         while(childList.iterator().hasNext()) 
         { 
          RealmObject listItem = (RealmObject)childList.iterator().next(); 
          RealmUtils.deleteCascade(listItem); 
         } 
        } catch (Exception ex) { 
         Log.e("REALM", "CASCADE DELETE LIST: " + ex.toString()); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       Log.e("REALM", "CASCADE DELETE ITERATION: " + ex.toString()); 
      } 
     } 
    } 
    dataObject.deleteFromRealm(); 
} 

} 

2) In-Schnittstelle zu Ihrem Projekt. Wenn Ihr Realm-Objekt diese Schnittstelle implementiert, werden alle untergeordneten Objekte nach dem Aufruf von deleteCascade gelöscht. Wenn die Schnittstelle nicht implementiert ist, löscht diese Funktion Realm-Objekte, löscht jedoch keine untergeordneten Objekte.

public interface IRealmCascade { 
} 

3) Deklarieren Sie Ihr Realm-Objekt. Beispiel unten.

public class NodeModel extends RealmObject implements IRITSerializable, IRealmCascade { 
    @PrimaryKey 
    @SerializedName("id") private String objId; 
    @SerializedName("parentId") private String parentId; 
    @SerializedName("contentType") private String nodeType; 
    @Required 
    @SerializedName("name") private String name; 

    @SerializedName("settings") private RealmList<ValueTypeModel> columns; 

    public String getObjId() { 
     return objId; 
    } 

    public void setObjId(String objId) { 
     this.objId = objId; 
    } 

    public String getParentId() { 
     return parentId; 
    } 

    public void setParentId(String parentId) { 
     this.parentId = parentId; 
    } 

    public String getNodeType() { 
     return nodeType; 
    } 

    public void setNodeType(String nodeType) { 
     this.nodeType = nodeType; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public RealmList<ValueTypeModel> getColumns() { 
     return columns; 
    } 

    public void setColumns(RealmList<ValueTypeModel> columns) { 
     this.columns = columns; 
    } 
} 

4) Sie müssen RealmUtils.deleteCascade (realmObject nennen); stattdessen realmObject.removeFromRealm(); Beispiel unter Aktualisierungsdaten in der lokalen Datenbank

for(NodeModel nodeItem: incomingData.getNodesList()) 
{ 
    RealmResults<NodeModel> results = bgRealm.where(NodeModel.class).equalTo("objId", nodeItem.getObjId()).findAll(); 
    if (results.size() > 0) 
    { 
     RealmUtils.deleteCascade(results.first()); 
    } 
    bgRealm.copyToRealm(nodeItem); 
} 

Genießen Sie Ihre saubere DB! :)

+1

Denken Sie daran, dass dieser Code, obwohl er funktioniert, sehr langsam ist, also wenn Sie einen schnellen Ansatz benötigen, ist es besser, Tabelle für Tabelle oder Tabelle mit ID nach Tabelle mit ID – iGoDa

+0

zu löschen Ja, es wird langsam für große Datenmengen aber es ist schnell genug für die meisten Bedürfnisse. Wenn Sie große Datenmengen löschen müssen - zum Beispiel einige tausend Datensätze -, führen Sie es einfach im Hintergrundthread aus. –

+0

Stimmt, ich wollte nur andere davor warnen. – iGoDa

0

Ich habe eine Variation dieser Implementierung, die andere nützlich finden könnten.

In der ursprünglichen Implementierung: RealmObject-Unterklassen, die traversierbar sein sollen "implementieren IRealmCascade". Alle RealmObjects, die die Schnittstelle nicht implementieren, werden als Blattknoten behandelt (das Objekt wird gelöscht, die untergeordneten Objekte jedoch nicht).

In meiner Implementierung: Any RealmObject/RealmList ist verfahrbar (sie müssen keine Schnittstelle implementieren). Wenn die Klasse über ein Mitglied verfügt, das nicht durchlaufen werden soll, wird der Getter für dieses Mitglied mit "@SkipDelete" kommentiert.

/** 
* Traverse the tree of RealmObjects, deleting the RealmObject/RealmList children 
* and the root RealmObject. 
* <br><br> 
* This method uses reflection to get the rootObject's "getter" methods. The 
* getter methods are called to get the RealmObject/RealmList children, and 
* those objects are deleted from the Realm. 
* <br><br> 
* If any of the getter methods return a RealmObject/RealmList that should NOT be 
* deleted, those getter methods should be annotated with {@link SkipDelete}. 
* 
* @param rootObject The root of the RealmObject tree 
*/ 
public static void delete(RealmObject rootObject) { 
    if (rootObject == null) { 
     return; 
    } 

    for (Method method : rootObject.getClass().getSuperclass().getDeclaredMethods()) { 
     try { 
      // Ignore non-getter methods 
      boolean noParams = method.getParameterTypes().length == 0; 
      if (!(method.getName().startsWith("get")) || !noParams) { 
       continue; 
      } 

      // Ignore primitive members 
      Class<?> resultType = method.getReturnType(); 
      if (resultType.isPrimitive()) { 
       continue; 
      } 

      // Ignore methods annotated with SkipDelete 
      if (method.isAnnotationPresent(SkipDelete.class)) { 
       continue; 
      } 

      if (RealmObject.class.isAssignableFrom(resultType)) { 
       // getter method returns a RealmObject, delete it 
       try { 
        RealmObject childObject = (RealmObject) method.invoke(rootObject); 
        delete(childObject, true); 
       } catch (Exception ex) { 
        Log.e("delete: RealmObject " + resultType.getSimpleName(), ex); 
       } 

      } else if (RealmList.class.isAssignableFrom(resultType)) { 
       // getter method returns a RealmList, delete the objects in the list 
       try { 
        RealmList childList = (RealmList) method.invoke(rootObject); 
        while (childList.iterator().hasNext()) { 
         RealmObject listItem = (RealmObject)childList.iterator().next(); 
         delete(listItem, true); 
        } 
       } catch (Exception ex) { 
        Log.e("delete: RealmList " + resultType.getSimpleName(), ex); 
       } 
      } 
     } 
     catch (Exception ex) { 
      Log.e("delete: ", ex); 
     } 
    } 

    rootObject.deleteFromRealm(); 
} 

/** 
* This annotation is used to mark a "getter" method that should be skipped 
* over on the cascading delete traversal of the RealmObject/RealmList tree. 
*/ 
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface SkipDelete { 
} 

In Ihrem RealmObject

public class Design extends RealmObject { 
    private MyRealmObject1 obj1;  // do CascadeDelete on this member 
    private MyRealmObject2 obj2;  // don't do CascadeDelete on this member 

    .... 

    public MyRealmObject1 getObj1() { 
     return obj1; 
    } 

    @CascadeDelete.SkipDelete   // don't do CascadeDelete of obj2 
    public MyRealmObject2 getObj2() { 
     return obj2; 
    } 
}