2016-05-02 96 views
4

我對領域進行了「級聯刪除」操作。可悲的是,該功能尚未實現。我做了我自己的實現並在此分享。Android上的領域「級聯刪除」

如何爲Realm「級聯刪除」操作製作通用代碼?

+1

Stack Overflow是編程問題。你的問題是什麼? – CommonsWare

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

享受你的清潔DB! :)

+1

請記住,此代碼雖然工作,但會很慢,所以如果您需要一個快速的方法,最好刪除表或表的id與表編號爲 – iGoDa

+0

是的,它會緩慢的大數據量,但它的速度足夠滿足大部分需求。如果您需要刪除大量數據 - 例如數千條記錄 - 只需在後臺線程中運行即可。 –

+0

的確,我只是想警告其他人。 – iGoDa

0

我對這個實現有一個變體,其他人可能會覺得有用。

在原來的實現中:要穿越的RealmObject子類「實現IRealmCascade」。任何不實現該接口的RealmObjects將被視爲葉節點(該對象將被刪除,但它的子節點不會)。

在我的實現中:任何RealmObject/RealmList都是可遍歷的(它們不需要實現任何接口)。如果該類有一個不被遍歷的成員,則該成員的getter用「@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'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; 
    } 
}