Room数据库中具有相同类型对象的多个表格

45

我正在使用Room作为应用程序的数据库。我有一种情况,需要将某种类型的Object存储在不同的表中。例如,让我们来看看名为Book.javaObject

现在,我想要有两个SQL表:

  • Books_Read
  • Books_To_Read

请忽略任何命名约定,这只是一个例子

问题

通常,人们会在Book.java类中使用@Entity(tableName = "Books_Read"),并拥有一个使用该表名的DAO类。

问题在于;如果我想将同一Book.java类用于存储在Books_To_Read表中,我该怎么做呢?由于我已经在Book.java类中定义了@Entity(tableName = "Books_Read"),并且我看不到在Book.java类中定义Books_To_Read表的地方

我唯一能想到的解决方案似乎有点hackery和不必要,那就是创建一个新类-让我们称之为BookToRead.java,它继承Book.java并在类中定义@Entity(tableName = "Books_To_Read")

问题

是否有更好的方法来处理这个问题,或者这是处理它的预期方式?


4
我的意思是,如果它是相同的实体,为什么你还想要不同的表呢?我认为应该是同一个表,只需添加额外的列,比如“to_read”或其他名称。 - romtsn
@rom4ek 你说得对。我发帖后很快就意识到了这一点。最终,我通过使用一个表格并添加一个新列来区分不同类型来解决了这个问题。 - Robert J. Clegg
我不确定这是否仅与此特定情况有关,但是在表中添加一个额外的字段/列来告诉书是否已读,这样做不行吗?为什么要将它们存储在不同的表中? - Ionut J. Bejan
我有一个类似的问题。数据在24小时后可能会变得陈旧,因此我会在此时间后删除所有保存的数据。因此,在删除时,我将删除我是否已经收藏了该对象(删除存储在对象中的布尔变量)。因此,我可能需要另一个表和/或共享首选项中的标志。目前也在使用Room。 - filthy_wizard
4个回答

40

这是应对它的预期方式吗?

不是。这是一种错误的方法。你应该消除数据重复,原因有几个。

  • 它将耗费存储空间。随着数据库的大小增加,这将变得更糟。

  • 它会使系统变得复杂。如果您正在更新单个字段,则可能必须在不同的位置执行相同的操作。如果您错过了其中任何一个,整个数据将变得不一致。可以将此类操作作为单个事务执行。但最好保持数据库结构的清晰性。


解决方案

方法1:引入新表

您可以仅在一个表中存储书籍详细信息,例如"Books""Books_To_Read"或任何其他表只应包含对"Books"表的引用(通过使用"Books"表中的id /主键)。然后,您可以使用JOIN关键字以一次查询获取整个记录。

如果每种类型(在本例中为已读和未读书籍)都具有自己的字段集(例如,已读书籍的read_date,read_time和未读书籍的wish_to_read),则应首选此方法。

方法2:引入新字段

您可以简单地添加一个指定类型的新类型。在这种情况下,只有两种类型(已读和未读),一个布尔字段(例如像is_read)就足够了。

这将是最简单的方法。但如果您只想指示行属于哪种类型,则会起作用。如果确实需要存储类型特定数据并为此目的引入其他字段,请记住这些字段也将存在于其他类型中。


我非常理解并喜欢方法2。但是我对方法1的理解有些困难。您能否用示例或链接我到适当的文档来更详细地解释一下? - Cyber Avater

2
这就是我最终解决问题的方法:
我在 Book.java 类中添加了一个表示书籍是否已读的 ID。该 ID 由 EnumType 支持,可以是 book_readbook_unread。然后在我的 "BooksDataTable"DAO 中,我只需要使用 SQL 查询 来选择所需的 ID。因此只需更改查询,就可以获取所有阅读过的书籍或待阅读的书籍或所有书籍。这样,就不会有数据重复,并且所有数据都在一个表格中,而不需要使用 JOINOneToMany 关系。

1

当Ahamad回答时,我正在编写示例应用程序。

Room提供了一个抽象层,可以在利用SQLite的全部功能的同时允许流畅地访问数据库。

主要思想与将书籍数据存储在一张表中并在其他表中使用书籍ID的思想相同。请查看我的示例项目

logcat的结果

02-19 16:39:26.741 10520-10520/com.example.jingged.roomtest E/MainActivity: Book{id = 1 name = Book 0, author Author 0}
02-19 16:39:26.741 10520-10520/com.example.jingged.roomtest E/MainActivity: Book{id = 2 name = Book 1, author Author 1}
02-19 16:39:26.741 10520-10520/com.example.jingged.roomtest E/MainActivity: Book{id = 3 name = Book 2, author Author 2}
02-19 16:39:26.741 10520-10520/com.example.jingged.roomtest E/MainActivity: Book{id = 4 name = Book 3, author Author 3}
02-19 16:39:26.767 10520-10520/com.example.jingged.roomtest E/MainActivity: BookToRead Book{id = 3 name = Book 2, author Author 2}
02-19 16:39:26.767 10520-10520/com.example.jingged.roomtest E/MainActivity: BookToRead Book{id = 4 name = Book 3, author Author 3}
02-19 16:39:26.768 10520-10520/com.example.jingged.roomtest E/MainActivity: BooksRead Book{id = 1 name = Book 0, author Author 0}
02-19 16:39:26.768 10520-10520/com.example.jingged.roomtest E/MainActivity: BooksRead Book{id = 2 name = Book 1, author Author 1}

这只是复制相同的代码并仅更改表名吗? - Shawn Thye

-3
@OneToMany(mappedBy="book_id")
private Set<Book> book

我认为这是连接两个表的最佳方式。试一下并告诉我你的反馈。我会提供另一个解决方案。


这并没有回答问题。 - Max
1
你没有读懂他的问题...哈哈 - Shawn Thye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接