Наследование в библиотеке комнат сохраняемости - PullRequest
0 голосов
/ 15 мая 2019

TL; DR: Как я могу хранить и извлекать объекты типа ClassA и ClassB, которые оба наследуются от ClassP в одном и том же «списке», используя Библиотеку постоянства помещения?

Другими словами, Как мне сохранить List<? extends BaseAnimal> в моей комнате DB?


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

public abstract class BaseAnimal {
    @PrimaryKey(autoGenerate = true)
    private long id;

    public BaseAnimal(long id){this.id = id;}

    public abstract void func(int param);

    public long getId() {
        return id;
    }
}

Животное имеет id и реализует некоторую функцию func. Там, вероятно, будет много видов животных. Для начала у меня есть Elephant, который дополнительно имеет свойство trunkLength, и Giraffe, который дополнительно имеет свойство neckLength.

public class Giraffe extends BaseAnimal {
    public long neckLength;

    public Giraffe(long id) {
        super(id);
    }

    @Override
    public void func(int param) {

    }
}

У меня есть несколько экземпляров Elephant и Giraffe в моем приложении. Как я могу, используя библиотеку постоянства Android Room, сохранять и извлекать их, отсортированные по BaseAnimal.id?


Ожидания

Сначала я надеялся, что все будет так просто:

  • Аннотируйте класс BaseAnimal с помощью @Entity(tableName = "base_animal_table")

  • Аннотируйте мое расширение RoomDatabase с @Database (entity = {BaseAnimal.class}, версия = 1)

  • Добавить функцию для вставки в объект доступа к данным
    @Insert void insertAnimal(BaseAnimal animal);

  • Добавить метод в репозиторий

    public void insertAnimal(BaseAnimal animal){
            new insertAnimalAsyncTask(recipeDAO).execute(animal);
        }
    
    private static class insertAnimalAsyncTask extends AsyncTask<BaseAnimal, Void, Void> {
    
        private RecipeDAO mAsyncTaskDao;
    
        insertAnimalAsyncTask(RecipeDAO dao) {
            mAsyncTaskDao = dao;
        }
    
        @Override
        protected Void doInBackground(final BaseAnimal... params) {
            mAsyncTaskDao.insertAnimal(params[0]);
            return null;
        }
    }
    

Я ожидал, что это приведет к созданию комнаты с именем base_animal_table, которая будет выглядеть примерно так (с некоторыми примерами данных):

| id | ElephantTrunkLength | GiraffeNeckLength |
| 0  | NULL                | 12                |
| 12 | 1337                | NULL              |

Я также ожидал, что смогу получить данные из этой таблицы примерно так:

// this is in the DAO
@Query("SELECT * from `base_animal_table` ORDER BY id ASC")
LiveData<List<BaseAnimal>> getAllAnimals();

, а затем получите список, содержащий как сущности типа Elephant с установленным свойством trunkLength, так и сущности типа Giraffe с установленным neckLength. Кажется, это не так просто. Как я могу это реализовать?


Один из подходов, который я вижу, заключается в следующем, но я не уверен, что это лучший способ. И я также начинаю сомневаться, что Room делает это проще, чем простой SQLite. Я попытался создать рабочий пример для этого подхода с пространством, но все еще есть некоторые нерешенные проблемы.

Один подход

Создайте таблицу base_animals, которая содержит только id и другие атрибуты базовых животных, а также указатель их дочернего типа:

// base_animals
| id | animalType |
| 0  | "GIRAFFE"  |
| 12 | "ELEPHANT" |

Используйте эту таблицу, чтобы вести список всех животных и их id с. Создайте таблицу elephants и таблицу giraffes с id и их специфическими свойствами (trunkLength и neckLength соответственно). Затем мы можем сохранить животное в БД, создав запись в базовой и дочерней таблицах.
Чтобы извлечь конкретное животное по id, теперь мы можем найти animalType в таблице base_animals и с этим решить, в какой дочерней таблице - elephants или giraffes нам нужно искать.

Проблема, связанная с этим подходом, заключается в том, что он требует от меня написания некоторого кода и его обновления всякий раз, когда я создаю новую сущность животного - например, Dolphin.

Итак, мой вопрос: Как мне хранить List<? extends BaseAnimal> в моей комнате DB?
Я бы предпочел, чтобы я мог оставить BaseAnimal абстрактный класс.

1 Ответ

0 голосов
/ 15 мая 2019

Я не уверен, что использование наследования - это хорошая идея.Вместо этого я бы предложил использовать состав.

Оставьте класс с именем Animal (не BaseAnimal).

У животного должен быть тип, подобный тому, который вы предложили.

Другая таблица (AnimalProperties) будет держать свойства каждого животного.Он будет иметь внешний ключ к таблице Animals, а также имя свойства и значение свойства.

Now ...

Если это все, что вам нужно, то есть класс с типом и свойствами, тогдавсе готовоНо если вам также нужно, чтобы класс вел себя по-разному, как реализация метода fly () для птицы и запуска () собаки, тогда вам следует рассмотреть возможность использования Composition для добавления поведения в Animal.

Если вы не знакомыс Композицией посмотрите здесь для простого объяснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...