领域"级联删除"在Android上

时间:2016-05-02 22:36:25

标签: android realm cascading-deletes

我搜索了"级联删除"境界的运作。遗憾的是,该功能尚未实施。我自己实现了它并在这里分享了它。

如何为Realm制作通用代码"级联删除"操作?

2 个答案:

答案 0 :(得分:2)

1)将此代码复制到您的项目

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)为项目添加界面。如果您的Realm对象实现此接口,则在调用deleteCascade后将删除所有子对象。如果接口未实现此功能,则删除Realm对象但不删除子对象。

public interface IRealmCascade {
}

3)声明你的Realm对象。示例如下。

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

享受您干净的数据库! :)

答案 1 :(得分:0)

我对此实现有一些变化,其他人可能会觉得有用。

在原始实现中:要遍历的RealmObject子类&#34;实现IRealmCascade&#34;。任何未实现该接口的RealmObject都将被视为叶节点(该对象将被删除,但其子节点不会被删除)。

在我的实现中:任何RealmObject / RealmList都是可遍历的(它们不需要实现任何接口)。如果该类具有不被遍历的成员,则该成员的getter使用&#34; @ SkipDelete&#34;进行注释。

/**
 * 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 {
}

在你的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;
    }
}