问题描述
TL; DR:如何使用Room Persistence库在同一个列表"中存储和检索都继承自ClassP
的ClassA
和ClassB
类型的对象?
TL;DR: How can I store and retrieve objects of type ClassA
and ClassB
which both inherit from ClassP
in the same "list", using the Room Persistence Library?
换句话说,我应该如何在房间DB中存储List<? extends BaseAnimal>
?
In other words, How should I store a List<? extends BaseAnimal>
in my Room DB?
出于这个问题的目的,我有动物.
I have Animals, for the purpose of this question.
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
属性.
An animal has an id
and implements some function func
. There will likely be many kinds of animals. To start with, I have an Elephant
which additionally has a trunkLength
property, and a Giraffe
which additionally has a neckLength
property.
public class Giraffe extends BaseAnimal {
public long neckLength;
public Giraffe(long id) {
super(id);
}
@Override
public void func(int param) {
}
}
我的应用程序中有几个Elephant
和Giraffe
实例.如何使用Android Room Persistence Library存储和检索按BaseAnimal.id
排序的它们?
I have several instances of Elephant
and Giraffe
in my application. How can I, using the Android Room Persistence Library, store and retrieve them sorted by BaseAnimal.id
?
起初,我希望它会像这样简单:
At first, I hoped that it would be as simple as this:
-
用
@Entity(tableName = "base_animal_table")
用注释RoomDatabase
的扩展名 @Database(entities = {BaseAnimal.class},版本= 1)
Annotate my extension of the RoomDatabase
with @Database(entities = {BaseAnimal.class }, version = 1)
添加用于插入数据访问对象的功能
@Insert void insertAnimal(BaseAnimal animal);
Add a function for inserting to the Data Access Object
@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
的表,该表看起来像这样(带有一些示例数据):
I expected that this would lead to room generating a table named base_animal_table
which would look somewhat like this (with some sample data):
| id | ElephantTrunkLength | GiraffeNeckLength |
| 0 | NULL | 12 |
| 12 | 1337 | NULL |
我还希望我可以从该表中检索数据,如下所示:
I also expected that I could retrieve the data from this table something like this:
// this is in the DAO
@Query("SELECT * from `base_animal_table` ORDER BY id ASC")
LiveData<List<BaseAnimal>> getAllAnimals();
,然后获得一个列表,该列表包含设置为trunkLength
的类型为Elephant
的实体和设置为neckLength
的类型为Giraffe
的实体.这似乎并不简单.我该如何实施?
and then get a list that contains both, entities of type Elephant
with their trunkLength
property set, and entities of type Giraffe
with their neckLength
set.This seems not to be straightforward. How can I implement this?
我看到的一种方法是以下方法,但是我不确定这是否是最佳方法.而且我也开始怀疑Room是否比使用普通的SQLite更容易.我尝试为这种方法留出空间,并给出了一个可行的示例,但是仍然存在一些未解决的问题.
One approach I see is the following, but I am not sure whether it is the best way. And I am also starting to doubt that Room makes this any easier than using plain SQLite. I tried to produce a working example for this approach with room, but there are still some unresolved issues.
创建一个表base_animals
,该表仅包含id
和其他基本动物属性以及其子类型的指示符:
Create a table base_animals
which only contains the id
and other base animal attributes, along with an indicator of their child type:
// base_animals
| id | animalType |
| 0 | "GIRAFFE" |
| 12 | "ELEPHANT" |
使用此表保留所有动物及其id
的列表.创建具有id
及其特定属性(分别为trunkLength
和neckLength
)的表elephants
和表giraffes
.然后,我们可以通过在基表和子表中都创建一个条目,将动物存储在数据库中.
要通过id
检索特定动物,我们现在可以在base_animals
表中找到animalType
,并决定要在哪个子表-elephants
或giraffes
中进行搜索.
Use this table to keep a list of all animals and their id
s. Create a table elephants
and a table giraffes
with the id
and their specific properties (trunkLength
and neckLength
, respectively).Then we can store an animal in the DB by creating an entry in both the base table and the child table.
To retrieve a specific animal by id
, we can now find the animalType
in the base_animals
table and with that decide in which child table - elephants
or giraffes
we need to search.
此方法的问题在于,它要求我必须编写一些代码,并且每当创建新的动物实体时都必须对其进行更新-例如Dolphin
.
The problem I have with this approach is that it requires that I have to write quite some code and I have to update it whenever I create a new animal entity - e.g. a Dolphin
.
所以,我的问题是:我应该如何在房间DB中存储List<? extends BaseAnimal>
?
如果可以将BaseAnimal
保留为抽象类,我会更喜欢.
So, my question is: How should I store a List<? extends BaseAnimal>
in my Room DB?
I would prefer it if I could leave BaseAnimal
an abstract class.
推荐答案
我不确定在这里使用继承是个好主意.我建议改用合成.
I'm not sure that using inheritance is a good idea here.I would suggest using composition instead.
保留一个名为Animal(不是BaseAnimal)的类.
Keep a class named Animal (not BaseAnimal).
动物的类型应该与您建议的一样.
The animal should have a type just like you suggested.
另一个表(AnimalProperties)将保存每个动物的属性.它将具有动物"表的外键以及属性名称和属性值.
Another table (AnimalProperties) would hold the properties of each animal.It will have a foreign key to the Animals table and a property name and property value.
现在...
如果这就是您所需要的,这意味着一个具有类型和属性的类,那么您就准备就绪了.但是,如果您还需要类的行为不同,例如为鸟实现fly()方法并为狗实现run(),则应考虑使用Composition为动物添加行为.
If this is all that you need, meaning a class with type and properties then you're all set.But if you also need the class to behave differently like implementing a fly() method for a bird and run() a dog then you should consider using Composition to add behaviors to the Animal.
如果您不熟悉Composition,请在此处进行简单说明
If you are not familiar with Composition have a look here for a simple explanation.
这篇关于房间持久性库中的继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!