【问题标题】:Deconflict column names in "join" entity“加入”实体中的列名冲突
【发布时间】:2022-01-17 09:47:46
【问题描述】:

我有 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”属性冲突?

【问题讨论】:

    标签: android android-room android-room-relation android-room-embedded


    【解决方案1】:

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

    例如使用:-

    @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。

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

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

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

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

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

    【讨论】:

    • 谢谢!至于唯一名称,大多数时候这很容易,但几乎每个实体都有一个 id 字段,如果不在任何地方使用 id 并使用 author.authorId 和 book.bookId,那就太糟糕了。
    • @lostintranslation 用更简单的解决方案和解释更新了答案。
    • 再次感谢@MikeT。尽管您的第一个答案更简单,但它假定所有书籍 ID 都是唯一的。就我而言,我可能有不同作者的重复图书 ID。
    • 请注意,仍在努力编译您的第二个示例。实体上不存在“book.author”,因此需要更改。还会遇到编译器找不到要调用的构造函数的问题。我想我已经在查询中设置了所有属性,所以不确定这里发生了什么。
    • @lostintranslation * 我想我已经在查询中设置了所有属性,所以不完全确定这里发生了什么* 我已经编辑了答案,它基于成功的构建/编译并且可能还解释一些可能发生的事情,也许还有前进的道路。
    【解决方案2】:

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

    我的理解是这是one to many relationship:一位作者(父母)拥有零个或多个书籍(实体)。

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

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

    @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 列来解决歧义。
    • 由于图书 ID 可以重复,我们需要引入一个新列作为图书的 PrimaryKey。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多