2017-02-15 3 views
2

Я рассматриваю Realm как решение для базы данных по разным причинам, но большая из них в настоящее время является TransactionTooLargeException, которая теперь выбрасывается в Nougat, поэтому я должен переделать свою текущую архитектуру базы данных, основанный на ActiveAndroid, который имеет свои собственные досадные ограничения. Трудность состоит в том, что Realm не поддерживает наследование (https://github.com/realm/realm-java/issues/761), и они не кажутся в какой-то конкретной спешке, чтобы обойти его. Вместо этого они рекомендуют использовать состав над наследованием, но я не могу понять, как это сделать с десериализацией Gson/Json.Композиция над наследованием для RealmObjects с сериализацией Gson

Пример:

суперкласса: Животное, с подклассами собачкой и немецкая овчарка

public class Animal { 

    private int numLegs; 

    private boolean hasFur; 
} 

public class Dog extends Animal { 
    private String color; 

    private boolean canDoTricks; 
} 

public class GermanShepherd extends Dog { 

    public boolean isGuardDog; 

    public boolean isAtRiskOfHipDysplasia() 
} 

(К сожалению, это супер консервированный пример, только для иллюстрации).

Теперь скажем, для JSON это выглядит следующим образом:

{ 
    "numLegs" : 4, 
    "hasFur" : true, 
    "color" : "Black & Brown", 
    "canDoTricks" : true, 
    "isGuardDog" : true, 
    "isAtRiskofHipDysplasia" : false 
} 

Теперь я не могу изменить JSon, потому что это API, который дает мне.

Глядя на этот ответ: https://stackoverflow.com/a/41552457/4560689, кажется, что это очень опасный способ сделать его видом работы, но ответ отмечает, что существуют ограничения, в том числе, что сериализация будет неправильной. Поскольку сервер работает только в формате json, который не включает сумасшедшую композицию, это создает проблему.

Могу ли я написать собственный десериализатор/сериализатор Gson, чтобы сделать эту работу? Если да, то как это будет выглядеть? Я в основном должен иметь возможность конвертировать полезную нагрузку json в Объекты N, где N - 1 объекты вложены внутри базового объекта.

Так что с композицией (обратите внимание, что это не обязательно композиция «Царство», просто пример, так как похоже, что в Realm нужно использовать какую-то странную форму интерфейса-композиции), у меня будет класс, как показано ниже:

public class GermanShepherd { 
    public Animal animal; 
    public Dog dog; 

    // Generate a bunch of delegate methods here 
} 

Я лаю неправильное дерево? Похоже, что Realm может не работать для того, что я пытаюсь сделать, и наследование встроено в API, который я использую в нескольких местах, и конкретно в объектах, которые я хочу сохранить, поэтому мне нужно либо выяснить способ обхода или использовать другое решение. ActiveAndroid (то, что я использую сейчас) также является менее идеальным решением, и я болен до смерти, когда сталкиваюсь с обходом вокруг тупиков, сбоями, опросом фоновых потоков, которые теперь вызывают сбои, если данные слишком велики, чтобы пройти в Intent и т. Д. ... все проблемы с SQLite. Я открыт для решения моего основного вопроса или альтернатив, которые решают эту проблему. Заранее спасибо за вашу помощь!

+1

Я тот, кто написал ответ, который вы опубликовали. Ну, есть способ обойти это, создав GermanShepard POJO (non realmObject), который будет сериализован так, как вам нравится, с Gson и сделайте какое-то сопоставление между realmObject вашего GermanShepard и этим POJO. Фактически, это то, что делал ppl для решения этой проблемы. Проверьте [это] (http://johnpetitto.com/no-more-realm). Если вы хотите, чтобы я написал пример о том, как это сделать, просто скажите мне, и я отправлю код ^^. Но я бы порекомендовал пользовательские сериализаторы, это лучший подход. – AnixPasBesoin

+0

@AnixPasBesoin, спасибо за ответ! Я бы хотел, если это возможно, сделать пользовательские сериализаторы. У вас есть представление о том, как я могу сделать эту работу? Я просто использую Gson, как ранее, для десериализации ответа API в RealmObject, а затем сериализует RealmObject обратно в формат json, который ожидает API? –

+0

Являются ли Gson и другие автосериализаторы странными для кого-либо еще? Лично я думаю, что предпочитаю просто сериализовать/десериализовать вручную ... некоторое повторение (нужно добавить новые поля в сериализатор и десериализатор), но я думаю, что это хороший уровень абстракции, который добавляет контроль и гибкость - обновление api не требуют обновления внутренних объектов объекта; как он разговаривает с api. –

ответ

3

Вы должны создать новый класс RealmObject для каждого сплющенного конкретного класса и сопоставить свое представление JSON с ними.

Чтобы сохранить наследование, вы можете имитировать его, наследуя геттеры/сеттеры от интерфейсов, которые наследуют друг от друга.

public interface IAnimal extends RealmModel {  
    int getNumberOfLegs(); 
    void setNumberOfLegs(int legs); 
    boolean getHasFur(); 
    void setHasFur(boolean hasFur); 
} 

public interface IDog extends IAnimal { 
    String getColor(); 
    void setColor(String color); 
    boolean getCanDoTricks(); 
    void setCanDoTricks(); 
} 

public interface IGermanShepherd extends IDog { 
    boolean getIsGuardDog(); 
    void setIsGuardDog(boolean isGuardDog); 
    boolean getIsAtRiskOfHipDysplasia(); 
    void setIsAtRiskOfHipDysplasia(boolean isAtRisk); 
} 

Потому что тогда вы можете сделать

public class GermanShepard 
    extends RealmObject 
    implements IGermanShepard { 
     private int numLegs; 
     private boolean hasFur; 
     private String color; 
     private boolean canDoTricks; 
     private boolean isGuardDog; 
     private boolean isAtRiskofHipDysplasia; 

     // inherited getters/setters 
} 

Вы можете даже сделать класс репозитория из него

public abstract class AnimalRepository<T extends IAnimal> { 
    protected Class<T> clazz; 

    public AnimalRepository(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    public RealmResults<T> findAll(Realm realm) { 
     return realm.where(clazz).findAll(); 
    } 
} 

@Singleton 
public class GermanShepardRepository extends AnimalRepository<GermanShepard> { 
     @Inject 
     public GermanShepardRepository() { 
      super(GermanShepard.class); 
     } 
} 

А потом

@Inject 
GermanShepardRepository germanShepardRepository; 

RealmResults<GermanShepard> results = germanShepardRepository.findAll(realm); 

Но вы действительно можете объединить их в один класс, а затем дать ему параметр String type;, чтобы узнать, какой тип он был первоначально. Вероятно, это даже лучше, чем наличие всех этих немецких пар.

+0

Если я правильно понимаю, GermanShepherd расширяет RealmObject и реализует RealmModel. Почему это? –

+0

Объявление 'RealmObject' фактически' @RealmClass public abstract class RealmObject реализует RealmModel', поэтому это не должно быть проблемой. Это сделать 'RealmResults ' работать в репозитории животных. Также я на самом деле не проверял это, но я думаю, что он должен работать. – EpicPandaForce

+0

Но это звучит как прецедент ["если вам действительно нужен полиморфизм, вы можете делиться полями RealmObject через интерфейс"] (https://hackernoon.com/designing-the-schema-of-realm-effectively- and-other-realm-tips-feb76c5b6072 # .32hs6ed05) – EpicPandaForce

Смежные вопросы