【问题标题】:LiveData and room using inheritanceLiveData 和 room 使用继承
【发布时间】:2021-09-24 06:49:18
【问题描述】:

我有一个我正在尝试编写的应用程序,它有 3 个从一个对象继承的对象,所有实体, 我正在使用空间来在本地存储它们。

在每个实体的 dao 中,我都有返回 livedata 的“getAll”函数。

我的问题是, 有没有办法从数据库中获取所有列表作为一个列表(因为它们都继承自同一个类)?

除非我错了,如果我只在超类上使用“getAll”,它不会给我每个类的特定字段。 我有一个 recyclerView 将这些对象保存为 1 个列表,所以我需要一种方法来组合它们。

我尝试查找它,但是当涉及到继承时,它并不清楚 Room 是如何处理东西的。(例如,在文档中,谷歌给出了一个使用继承的示例,其中两个对象都具有 uniqe id,但是当我尝试时出现错误超类 id 将被子类 id 覆盖。)。

如果有人可以提供帮助,或者提供我可以了解更多信息的链接,我将不胜感激。

谢谢,祝你有美好的一天!

【问题讨论】:

    标签: android android-room android-livedata


    【解决方案1】:

    把它留在这里以防其他人需要它。

    有多种方法可以解决这个问题。

    • 第一个是使用 POJO,如他的回答中所述的“MikeT”。

    • 第二个是给超类添加一个“type”属性并获取整个 超类列表,并在运行时选择正确的对象并创建它。(使用 id 因为它是相同的)。 缺点是您多次访问数据库,这可以减少 表现。 (今天早上之前我想要的解决方案)

    • 第三种方式(我最终使用)是“Danail Alexiev”的这篇帖子回答 Polymorphic entities in Room 创建一个压缩 2(或更多)的自定义 MediatorLiveData 实现 livedata 对象并返回一个。

    【讨论】:

      【解决方案2】:

      我相信您可以使用包含所有字段的 POJO(或者可能是合适的实体,如果存在的话)并使用包含 UNION 的 getAll@Query。当然,更好的方法或许是重新考虑设计。

      以下是一个父类 (BaseObject) 的示例,从其中继承了 2 个对象,名称为 ChildType1ChildType2

      在此示例中,ChildType2 具有 2 个附加字段,其中一个 ChildType1 具有唯一的附加字段。因此 ChildType2 适合保存 ChildType1 的所有字段。

      但是,要正确提取 ChildType1,它必须模仿 ChildType2 的附加字段>。这可以通过 Dao AlldaogetAll() 方法中的 SQL 轻松完成。

      以下是使用的代码:-

      BaseObject,两个 ChildType 继承自:-

      class BaseObject {
          @ColumnInfo(name = BaseColumns._ID)
          Long id;
          String name;
          long createdTimestamp = System.currentTimeMillis() / 1000;
          int type;
      }
      

      ChildType1 :-

      @Entity(primaryKeys = {BaseColumns._ID})
      class ChildType1 extends BaseObject {
          public static final int TYPE = 1;
          String ct1;
      }
      
      • 正如将看到的,id 列 (_id) 已被继承,后来它不会导致任何问题。

      ChildType2 :-

      @Entity(primaryKeys = {BaseColumns._ID})
      class ChildType2 extends BaseObject {
          public static final int TYPE = 2;
          String ct1;
          String ct2;
      }
      

      AllDao,所有的道都被编码了:-

      @Dao
      interface AllDao {
      
          @Insert
          long insert(ChildType1 childType1);
          @Insert
          long insert(ChildType2 childType2);
      
          @Query("SELECT *, 'n/a' AS ct2 FROM ChildType1 UNION SELECT * FROM childtype2")
          List<ChildType2> getAll();
      }
      
      • 查询正在使用最初 childtype1 表的 UNION 填充缺少的 ct2 字段,值为 n/a 和 childtype2 表。请注意,id 可能会被重复,因此要使用 id,您必须确定相应的类型 (例如,ct2 = n/a 那么它可能是 ChildType1(因此我会建议字符串类型的指示符)不能模棱两可))

      @Database TheDatabase :-

      @Database(entities = {ChildType1.class,ChildType2.class},version = 1)
      abstract class TheDatabase extends RoomDatabase {
          abstract AllDao getAllDao();
      
          private volatile static TheDatabase instance;
      
          public static TheDatabase getInstance(Context context) {
              if (instance == null) {
                  instance = Room.databaseBuilder(
                          context,
                          TheDatabase.class,
                          "thedatabase.db"
                  )
                          .allowMainThreadQueries()
                          .build();
                  instance.getOpenHelper().getWritableDatabase();
              }
              return instance;
          }
      }
      

      最后是一个 Activity,MainActivity 将它们放在一起进行演示:-

      public class MainActivity extends AppCompatActivity {
      
          TheDatabase db;
          AllDao dao;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              db = TheDatabase.getInstance(this);
              dao = db.getAllDao();
              ChildType1 c1_1 = new ChildType1();
              c1_1.name = "CT1 001";
              c1_1.ct1 = "This is a CT1 for CT1 001";
              c1_1.type = ChildType1.TYPE;
              dao.insert(c1_1);
              ChildType2 c2_1 = new ChildType2();
              c2_1.name = "CT2 002";
              c2_1.ct1 = "This is CT1 for CT2 002";
              c2_1.ct2 = "This is CT2 for CT2 002";
              dao.insert(c2_1);
              for(ChildType2 c: dao.getAll()) {
                  Log.d("" +
                          "TYPEINFO",
                          "Name = " + c.name +
                                  "\n\t Created = " + c.createdTimestamp +
                                  "\n\t ID = " + c.id +
                                  "\n\t type = " + c.type +
                                  "\n\t CT1 = " + c.ct1 +
                                  "\n\t CT2 = " + c.ct2
                  );
              }
          }
      }
      

      结果

      运行时日志包含:-

      D/TYPEINFO: Name = CT1 001
               Created = 1626589554
               ID = 1
               type = 1
               CT1 = This is a CT1 for CT1 001
               CT2 = n/a
      D/TYPEINFO: Name = CT2 002
               Created = 1626589554
               ID = 1
               type = 0
               CT1 = This is CT1 for CT2 002
               CT2 = This is CT2 for CT2 002
      

      即两种类型的孩子都被提取到一个可以包含所有字段的对象列表中。

      【讨论】:

      • 我已经考虑过这个解决方案,但我不想用“不必要的”对象使应用程序变得混乱,正如你所说,我开始重新考虑我的设计,但随后,我找到了另一个将 2 个 livedata 列表压缩在一起的解决方案要获取 1 个 livedata 对象,我在存储库层执行此操作,它会阻止我访问数据库两次,我得到了我需要的对象。我已经使用了这个帖子:stackoverflow.com/questions/51972843/… 在你回答的时候发现了它,所以我没有机会关闭帖子,无论如何,谢谢!
      猜你喜欢
      • 2019-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 2018-04-07
      • 1970-01-01
      相关资源
      最近更新 更多