[JAVA] Generische Transformationsgrammatik - RealmObject-Backup - Ich dachte, es wäre mühsam, RealmMigration während der Entwicklung zu schreiben, aber ich wollte die Daten übernehmen.

Der Anfang der Dinge

Ich mache derzeit eine Android-App mit Realm, möchte aber häufig mit der DB-Konfiguration herumspielen. ↓ Obwohl es sich um eine App in der Debugging-Phase handelt, ist es schwierig, Daten zu verlieren, da ich die App bereits praktisch verwendet habe. ↓ Das einzige, was Sie tun müssen, ist, die Anzahl der Spalten zu erhöhen. Daher ist es mühsam, die Realm-Migration einzeln zu überprüfen und zu schreiben. ↓ Ich denke, es ist besser, die Liste der RealmObjects zu jsonisieren, sie in den Einstellungen zu speichern, sie in RealmObject wiederherzustellen und sie zu aktualisieren. ↓ Lass es uns versuchen

Weg

Vorerst

ItemRealmObject

Dies ist eine gewöhnliche Objektklasse

Zugriffsklasse Erstellen Sie eine Klasse namens RealmHelper für den Zugriff

public class ItemRealmHelper extends AbstractRealmHelper {

    public static void insertOneShot(ItemRealmObject itemRealmObject) {
        executeTransactionOneShot(insertTransaction(itemRealmObject));
    }

    private static Realm.Transaction insertTransaction(final ItemRealmObject itemRealmObject) {
        return new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.insertOrUpdate(itemRealmObject);
            }
        };
    }

    @Override
    public void upsert(final ItemRealmObject item) {
        item.updateDate = new Date();
        executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealmOrUpdate(item);
            }
        });
    }

    @Override
    public RealmResults<ItemRealmObject> findAll() {
        return mRealm.where(ItemRealmObject.class).findAll();
    }
}
public abstract class AbstractRealmHelper<T extends RealmObject> {

    protected final Realm mRealm;

    public AbstractRealmHelper() {
        mRealm = getRealm();
    }

    static Realm getRealm() {
        return Realm.getInstance(new RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build());
    }

    protected static void executeTransactionOneShot(Realm.Transaction transaction) {
        Realm realm = getRealm();
        realm.executeTransaction(transaction);
        realm.close();
    }

    public abstract void upsert(T t);

    public abstract RealmResults<T> findAll();

    protected void executeTransaction(Realm.Transaction transaction) {
        mRealm.executeTransaction(transaction);
    }

    public void destroy() {
        mRealm.close();
    }
}

"Zuerst habe ich es einfach wieder in json ~ gesetzt", fühlte ich mich leicht.

Lesen Sie die Realm-Dokumentation https://realm.io/jp/docs/java/latest/#gson

GSON ist eine Google-Bibliothek, die JSON serialisiert / deserialisiert. GSON erfordert keine speziellen Einstellungen und kann so wie es ist mit Realm verwendet werden.

Das war's. Du kannst gehen.

Zunächst möchte ich es in den Einstellungen speichern, damit ich es sofort serialisieren kann.

new Gson().toJson(RealmObject);

Dann

StackOverFlowError

Es ist nicht gut ... Schauen Sie sich die Dokumentation noch einmal an.

In Bezug auf die Serialisierung können Realm-Objekte nicht mit den GSON-Standardeinstellungen serialisiert werden. Dies liegt daran, dass GSON Getter / Setter nicht verwendet und direkt auf Instanzvariablen verweist. Damit die JSON-Serialisierung von Realm-Objekten mit GSON ordnungsgemäß funktioniert, müssen Sie für jedes Modell einen benutzerdefinierten JsonSerializer und TypeAdapter schreiben. Der Code in dieser Liste zeigt, wie man sie schreibt.

Muss ich etwas schreiben ... Ich weiß es nicht. Kann eine Deserialisierung für RealmObject durchgeführt werden? Wenn···.

Also habe ich beschlossen, eine Modellklasse zu erstellen, die nicht dasselbe RealmObject ist, und sie in Json zu konvertieren. Erstellen Sie eine Modellklasse mit demselben Feldnamen und legen Sie sie so fest, dass Sie in jedes Feld einen Wert eingeben können, wenn Sie RealmObject an den Konstruktor übergeben. Erstellen Sie eine Liste von Modellklassen, indem Sie die von findAll of RealmHelper abgerufenen RealmResults mit einer for-Anweisung drehen, in Json konvertieren und in den Einstellungen speichern.

    void save() {
        writeData(PrefKey.itemRealm, new ItemRealmHelper());
        writeData(PrefKey.priceRealm, new PriceRealmHelper());
    }

    private <T extends RealmObject> void writeData(Enum key, AbstractRealmHelper<T> helper) {
        RealmResults<T> results = helper.findAll();
        List<Object> list = new ArrayList<>();
        for (T t : results) {
            list.add(getModel(t));
        }
        PreferenceUtils.writeValue(getContext(), key, JsonUtils.toJson(list));
        helper.destroy();
    }

    //Fügen Sie hier eine Beschreibung hinzu, wenn sie zunimmt
    private Object getModel(Object o) {
        if (o instanceof ItemRealmObject) {
            return new ItemModel((ItemRealmObject) o);
        } else if (o instanceof PriceRealmObject){
            return new PriceModel((PriceRealmObject) o);
        }
        throw new InternalError();
    }

(Dieser Code war ursprünglich etwas komplizierter, da ich ihn nach dem Erstellen der folgenden Lademethode überarbeitet habe.)

... Nun, die Rettung ging gut!

Nun, alles was Sie tun müssen, ist es zurückzusetzen

Schreiben Sie den Code, um ihn zurückzubekommen

ItemRealmHelper itemHelper = new ItemRealmHelper();
String json = PreferenceUtils.readValue(getContext(), PrefKey.itemRealm, "");
List<ItemRealmObject> itemModelList = new Gson().fromJson(json, new TypeToken<List<ItemRealmObject>>() {}.getType());
for (ItemRealmObject itemModel : itemModelList) {
    itemHelper.upsert(itemModel);
}

Oh, ich konnte gehen.

Ich denke hier jedoch darüber nach. "Ich mache einige RealmObjects. Wenn ich es also ehrlich schreibe, ist es nicht einfach, den Code so zu vergrößern, wie er ist, und es ist mühsam, den Typ jedes Mal zu kopieren und zu ändern ..."

//Wenn Sie es ehrlich schreiben, wird es zunehmen ...
void load() {
    ItemRealmHelper itemHelper = new ItemRealmHelper();
    String json = PreferenceUtils.readValue(getContext(), PrefKey.itemRealm, "");
    List<ItemRealmObject> itemModelList = new Gson().fromJson(json, new TypeToken<List<ItemRealmObject>>() {}.getType());
    for (ItemRealmObject itemModel : itemModelList) {
        itemHelper.upsert(itemModel);
    }
    itemHelper.destroy();
    
    Item2RealmHelper item2Helper = new Item2RealmHelper();
    String json2 = PreferenceUtils.readValue(getContext(), PrefKey.item2Realm, "");
    List<Item2RealmObject> item2ModelList = new Gson().fromJson(json, new TypeToken<List<Item2RealmObject>>() {}.getType());
    for (Item2RealmObject item2Model : item2ModelList) {
        item2Helper.upsert(item2Model);
    }
    item2Helper.destroy();
}
// ...Es nimmt jedes Mal zu, wenn es zunimmt

Mit den Worten ...

Generika kommen ins Spiel

Ich habe es geschafft, indem ich versucht habe, es zu einer Methode mit Upsert zu machen.

    private <T extends RealmObject> void upsert(Enum key, TypeToken<T> typeToken, final AbstractRealmHelper<T> helper) {
        List<T> list = new Gson().fromJson(PreferenceUtils.readValue(getContext(), key, ""), new TypeToken<List<T>>() {}.getType());
        for (T t : list) {
            helper.upsert(t);
        }
        helper.destory();
    }

Okay, ich habe es gut geschrieben. Also ausführen.

ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast

Was ist das ...

Als ich es nachgeschlagen habe, kam ein Artikel heraus.

Ich bin süchtig danach, JSON-Strings mit Gson in Generics-Objekte zu konvertieren http://osa030.hatenablog.com/entry/2015/10/20/182439

Wie Sie weiterlesen,

Das Ergebnis von Gson fromJson kann bis zur Hoge-Klasse dekodiert werden, der Wert lautet jedoch "com.google.gson.internal.LinkedTreeMap" anstelle der Fuga-Klasse.

Mit anderen Worten, es ist ein Listentyp, aber es scheint, dass das Ziel LinkedTreeMap ist.

Once your .java source file is compiled, the type parameter is obviously thrown away. Since it is not known at compile time, it cannot be stored in bytecode, so it's erased and Gson can't read it.

Kurz gesagt "" verschwindet zur Erstellungszeit, sodass es nicht dynamisch aussieht. Deshalb habe ich es mit Freundlichkeit zu Linked Tree Map geschafft.

Es gab einen StackOverFlow-Link.

Java Type Generic as Argument for GSON https://stackoverflow.com/questions/14139437/java-type-generic-as-argument-for-gson/14139700#14139700

Dies ist ein Beispiel, das ich in List konvertieren möchte, damit es zu mir passt.

Kopieren Sie ListOfSomething aus StackOverFlow und verwenden Sie es.

    private <T extends RealmObject> void upsert(Enum key, Class<T> clazz, final AbstractRealmHelper<T> helper) {
        List<T> list = new Gson().fromJson(PreferenceUtils.readValue(getContext(), key, ""), new ListOfSomething<>(clazz));
        for (T t : list) {
            helper.upsert(t);
        }
        helper.destory();
    }

Oh. erledigt. Es ist wunderbar.

Mit Blick auf den Inhalt gibt getRawType List.class fest zurück. Ich verstehe also, dass die Person im ersten Artikel die GenericOf-Klasse erstellt hat. Da es eine große Sache ist, werde ich es ändern (?) In Anbetracht der Vielseitigkeit.

    private <T extends RealmObject> void upsert(Enum key, Class<T> clazz, final AbstractRealmHelper<T> helper) {
        List<T> list = new Gson().fromJson(PreferenceUtils.readValue(getContext(), key, ""), new GenericOf<>(List.class, clazz));
        for (T t : list) {
            Footprint.fields(t);
            helper.upsert(t);
        }
        helper.destory();
    }

Es war das Erfrischendste.

Bei der Lademethode müssen Sie jetzt nur noch Upsert aufrufen, sodass von 7 Zeilen zu 1 Zeile gewechselt wird. Selbst wenn beispielsweise 2 RealmObjects vorhanden sind, fügen Sie jeweils nur eine Zeile hinzu!

void load() {
    upsert(PrefKey.itemRealm, ItemRealmObject.class, new ItemRealmHelper());
    upsert(PrefKey.item2Realm, Item2RealmObject.class, new Item2RealmHelper());
}

Es war erfrischend und einfach und ich war glücklich.

Zusammenfassung

    void save() {
        writeData(PrefKey.itemRealm, new ItemRealmHelper());
        writeData(PrefKey.priceRealm, new PriceRealmHelper());
    }

    private <T extends RealmObject> void writeData(Enum key, AbstractRealmHelper<T> helper) {
        RealmResults<T> results = helper.findAll();
        List<Object> list = new ArrayList<>();
        for (T t : results) {
            list.add(getModel(t));
        }
        PreferenceUtils.writeValue(getContext(), key, JsonUtils.toJson(list));
        helper.destroy();
    }

    //Fügen Sie hier eine Beschreibung hinzu, wenn sie zunimmt
    private Object getModel(Object o) {
        if (o instanceof ItemRealmObject) {
            return new ItemModel((ItemRealmObject) o);
        } else if (o instanceof PriceRealmObject){
            return new PriceModel((PriceRealmObject) o);
        }
        throw new InternalError();
    }
    void load() {
        upsert(PrefKey.itemRealm, ItemRealmObject.class, new ItemRealmHelper());
        upsert(PrefKey.item2Realm, Item2RealmObject.class, new Item2RealmHelper());
    }

    private <T extends RealmObject> void upsert(Enum key, Class<T> clazz, final AbstractRealmHelper<T> helper) {
        List<T> list = new Gson().fromJson(PreferenceUtils.readValue(getContext(), key, ""), new GenericOf<>(List.class, clazz));
        for (T t : list) {
            helper.upsert(t);
        }
        helper.destory();
    }

Schließlich

Ich war froh, TypeToken verwenden zu können, um eine Klasse anzugeben, die eine Liste in Gson enthält, aber als ich dort Generika einbezog, stellte ich fest, dass ich einen ParameterizedType benötigte. Sowohl Gson als auch Generics sind immer noch tief. Was ist, wenn Sie den Listentyp List mit Generika verwenden möchten? Ich dachte, aber es scheint gefährlich, also hörte ich auf zu denken. (Ist es in Ordnung, beide GenericsOf-Argumente auf TypeToken zu setzen ...?)

Wenn es so viel kostet, warum nicht JsonSerializer und TypeAdapter schreiben, damit RealmObject serialisiert werden kann? Ich dachte, es sei ein Geheimnis. War es nicht überhaupt schneller, Migration zu schreiben? Das ist geheimer. Es ist gut, weil ich gelernt habe ...

Recommended Posts

Generische Transformationsgrammatik - RealmObject-Backup - Ich dachte, es wäre mühsam, RealmMigration während der Entwicklung zu schreiben, aber ich wollte die Daten übernehmen.
Es war ein Leben, in dem ich den thread-sicheren assoziativen Zähler zurücksetzen wollte
Ich wurde viel von AWS während der Entwicklung auf Schienen berechnet, aber ...
Als ich eine Methode für Premium Friday erstellen wollte, war sie bereits in der Java 8-Standard-API enthalten