Realm cascading delete on Android

I did a search for a cascading delete operation for Realm. Unfortunately, this feature has not yet been implemented. I made my own implementation and shared it here.

How to create common code for cascading delete operation in Realm?

+4
source share
2 answers

1) Copy this code to your project

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) Add an interface to your project. If your Realm object implements this interface, all child objects will be deleted after the deleteCascade call. If the interface is not implemented, this function deletes the Realm object, but does not delete child objects.

public interface IRealmCascade {
}

3) Declare your Realm object. An example is below.

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) RealmUtils.deleteCascade(realmObject); realmObject.removeFromRealm();

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);
}

!:)

+2

, .

: RealmObject, , IRealmCascade. RealmObject, , ( , ).

: RealmObject/RealmList ( - ). , , "@SkipDelete".

/**
 * Traverse the tree of RealmObjects, deleting the RealmObject/RealmList children
 * and the root RealmObject.
 * <br><br>
 * This method uses reflection to get the rootObject "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 {
}

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;
    }
}
0

All Articles