0

我有 2 个实体:

@Entity(tableName = "author")
data class Author(
   @PrimaryKey
   @ColumnInfo(name = "id")
   val id: String,

   @ColumnInfo(name = "name")
   val name: String
)

data class Book(
   @ColumnInfo(name = "id")
   val id: String,

   @ColumnInfo(name = "title")
   val title: String,

   @ColumnInfo(name = "author_id")
   var authorId: String
)

我想加入他们的查询:

@Query("SELECT * FROM book JOIN author ON author.id = book.author_id AND author.id = :authorId WHERE book.id = :bookId")
fun item(authorId: String, bookId: String): LiveData<BookWithAuthor>

进入这个实体:

@Entity
data class BookWithAuthor(
        @Relation(parentColumn = "author_id", entityColumn = "id")
        val author: Author,

        @Embedded
        val book: Book
)

但是,当我这样做时,我会返回一个 BookWithAuthor 对象,其中 author.id 和 book.id 是相同的 id,在这种情况下它们都是作者的 id。如何消除“join”对象中实体中的“id”属性冲突?

4

2 回答 2

0

您可以使用@Embeddedprefix来消除名称的歧义。

例如使用:-

@Embedded(prefix="book_")
val book: Book

随着 :-

@Query("SELECT author.*, book.id AS book_id, book.title AS book_title, book.author_id AS book_author_id FROM book JOIN author ON author.id = book.author_id AND author.id = :authorId WHERE book.id = :bookId")
  • 请注意,以上是原则代码,尚未经过测试或运行。

然后,您将更改 BookWithAuthor 以使用前缀列:-

@Entity /* not an Entity i.e. Entity = table this just needs to be a POJO */
data class BookWithAuthor(
    @Embedded(prefix = "book_")
    val book: Book,
    /* with (makes more sense to have parent followed by child) */
    @Relation(/*entity = Author::class,*/ parentColumn = "book_author_id", entityColumn = "id")
    val author: Author
)

但是,您的评论假定所有书籍 ID 都是唯一的。就我而言,我可能有不同作者的重复书籍 ID。

似乎不适合您编码的表/实体(模式)。IE

  1. 作者实体很好。
  2. Book虽然没有 @Entity 注释,但如果它是在entities=[....]lis 中定义的实体,它也没有强制性的 @PrimaryKey 注释。所做的假设是 id 是/将是主键并相应地进行注释,因此是唯一的。
  3. BookWithAuthor您将看到 BookWithAuthor 已被注释为Not an Entity (table)。您不能将@Relationship注释放在定义为数据库实体的实体中(即注释entities=[....]列表中的类之一@Database)。

因此,除非 Book 实体/表的主键不是 id 或者 authorid 是作者列表,否则 Book 只能有一个作者。因此,您似乎只需要@Query("SELECT * FROM book WHERE id=:bookId"): LiveData<BookWithAuthor>

  • 如果不是,那么编码@Relation 将基本上忽略您的 JOIN 并选择所有作者,但然后只选择第一个任意作者来完成作者。那就是@Relation 通过获取父级然后构建它自己的底层查询来访问父级的所有子级来工作。因此,无论您提供什么查询,它都只能使用它来确定父母。

我怀疑您想要的是一本书可以有多个作者,并且一个作者可以是多本书的作者。在这种情况下,您通常会使用映射表(可以称为其他名称,例如链接、引用、关联......)。如果是这种情况并且您无法确定如何通过房间创建映射表,那么您可以在这方面提出另一个问题。

于 2021-12-14T01:54:56.733 回答
0

我认为这里的问题是定义关系。

我的理解是这是一对多的关系:一位作者(父母)有零个或多个书籍(实体)。

您的 @Relation 定义的是 1:1 关系。

如果你最终想要的是 BookWithAuthor,为什么不直接将 Author嵌入Book 中呢?然后,您将拥有以下表格:

@Entity(tableName = "author")
data class Author(
   @PrimaryKey
   @ColumnInfo(name = "author_id")
   val id: String,

   @ColumnInfo(name = "name")
   val name: String
)

@Entity(tableName = "BookWithAuthor")
data class Book(
   @PrimaryKey
   @ColumnInfo(name = "id")
   val id: String,

   @ColumnInfo(name = "book_id")
   val id: String,

   @ColumnInfo(name = "title")
   val title: String,

   @Embedded
   val author: Author   
)

您的查询可能如下所示:

@Query("SELECT * FROM BookWithAuthor WHERE book_id = :bookId AND author_id = :authorId")
fun item(authorId: String, bookId: String): LiveData<BookWithAuthor>
  • 嵌入后,Book 采用相同的 Author 列及其确切名称。所以我们至少需要重命名任何一个 id 列来解决歧义。
  • 由于 book id 可以重复,我们需要引入一个新列作为 Book 的 PrimaryKey。
于 2022-01-04T13:10:43.740 回答