2016-05-02 2 views
4

Я сделал поиск о операции «cascade delete» для Realm. К сожалению, эта функция еще не реализована. Я сделал свою собственную реализацию и поделился ею.Realm «cascade delete» на Android

Как создать общий код для операции «каскадное удаление» в Realm?

+1

переполнением стека для вопросов программирования. Какой у Вас вопрос? – 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

Имейте в виду, что этот код, хотя и работает, будет очень медленным, поэтому, если вам нужен быстрый подход, лучше удалить таблицу по таблице или таблице с идентификатором по таблице с идентификатором – iGoDa

+0

Да, это будет медленным для большого количества данных, но это достаточно быстро для большинства потребностей. Если вам нужно удалить большой объем данных - например, несколько тысяч записей - просто запустите его в фоновом потоке. –

+0

Правда, я просто хотел предупредить других об этом. – iGoDa

0

У меня есть вариант этой реализации, который другие могут найти полезной.

В исходной реализации: подклассы 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'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; 
    } 
}