我怎样才能代表Android Room的多对多关系?

我怎样才能代表与房间的多对多关系? 例如,我有“访客”和“预订”。 预订可以有许多客人,并且客人可以参加许多预订。

这是我的实体定义:

@Entity data class Reservation( @PrimaryKey val id: Long, val table: String, val guests: List ) @Entity data class Guest( @PrimaryKey val id: Long, val name: String, val email: String ) 

在查看文档时,我遇到了@Relation 。 我发现它真的很混乱。

根据这个,我想创建一个POJO并在那里添加关系。 所以,通过我的例子,我做了以下几点

 data class ReservationForGuest( @Embedded val reservation: Reservation, @Relation( parentColumn = "reservation.id", entityColumn = "id", entity = Guest::class ) val guestList: List ) 

上面我得到编译器错误:

无法弄清楚如何从游标中读取此字段。

我无法find@Relation的工作样本。

我有一个类似的问题。 这是我的解决方案。

您可以使用一个额外的实体( ReservationGuest )来保持GuestReservation之间的关系。

 @Entity data class Guest( @PrimaryKey val id: Long, val name: String, val email: String ) @Entity data class Reservation( @PrimaryKey val id: Long, val table: String ) @Entity data class ReservationGuest( @PrimaryKey(autoGenerate = true) val id: Long, val reservationId: Long, val guestId: Long ) 

您可以通过他们的guestId列表进行预订。 (不是客人对象)

 data class ReservationWithGuests( @Embedded val reservation:Reservation, @Relation( parentColumn = "id", entityColumn = "reservationId", entity = ReservationGuest::class, projection = "guestId" ) val guestIdList: List ) 

您还可以使用他们的reservationId列表获取客人。 (不是预订对象)

 data class GuestWithReservations( @Embedded val guest:Guest, @Relation( parentColumn = "id", entityColumn = "guestId", entity = ReservationGuest::class, projection = "reservationId" ) val reservationIdList: List ) 

由于您可以获取guestIdreservationId ,因此可以查询ReservationGuest实体。

如果我find一种简单的方法来获取Reservation和Guest对象列表而不是它们的id,我会更新我的答案。

类似的答案

这是一种通过单个查询中的M:N联结表查询完整对象模型的方法。 子查询可能不是最有效的方法,但它确实有效,直到他们让@Relation正确地遍历ForeignKey我将Guest / Reservation框架手动插入到我的工作代码中,因此可能存在拼写错误。

实体 (已涵盖)

 @Entity data class Guest( @PrimaryKey val id: Long, val name: String, val email: String ) @Entity data class Reservation( @PrimaryKey val id: Long, val table: String ) @Entity data class ReservationGuest( @PrimaryKey(autoGenerate = true) val id: Long, val reservationId: Long, val guestId: Long ) 

Dao (注意我们通过子查询拉入M:N并使用GROUP_CONCAT减少额外的Reservation

 @Query("SELECT *, " + "(SELECT GROUP_CONCAT(table) " + "FROM ReservationGuest " + "JOIN Reservation " + "ON Reservation.id = ReservationGuest.reservationId " + "WHERE ReservationGuest.guestId = Guest.id) AS tables, " + "FROM guest") abstract LiveData> getGuests(); 

GuestResult (它处理查询结果的映射,请注意我们将连接的字符串转换回带有@TypeConverter的列表)

 @TypeConverters({ReservationResult.class}) public class GuestResult extends Guest { public List tables; @TypeConverter public List fromGroupConcat(String reservations) { return Arrays.asList(reservations.split(",")); } } 

基于上面的答案: https : //stackoverflow.com/a/44428451/4992598只有在实体之间保留单独的字段名称才能返回模型(不仅仅是ids)。 您需要做的就是:

 @Entity data class ReservationGuest( @PrimaryKey(autoGenerate = true) val id: Long, val reservationId: Long, @Embedded val guest: Guest ) 

只要您不保留重复字段,就可以将实体嵌入到另一个实体中。 因此,ReservationWithGuests类看起来像这样。

 data class ReservationWithGuests( @Embedded val reservation:Reservation, @Relation( parentColumn = "id", entityColumn = "reservationId", entity = ReservationGuest::class, projection = "guestId" ) val guestList: List ) 

因此,此时您可以使用val guestIdList:List,因为您的ReservationGuest实体实际上将ID与实体模型映射。

实际上还有一种可能性来获取Guest列表,而不仅仅是像@Devrim一样的id。

首先定义将代表GuestReservation之间连接的类。

 @Entity(primaryKeys = ["reservationId", "guestId"], foreignKeys = [ ForeignKey(entity = Reservation::class, parentColumns = ["id"], childColumns = ["reservationId"]), ForeignKey(entity = Guest::class, parentColumns = ["id"], childColumns = ["guestId"]) ]) data class ReservationGuestJoin( val reservationId: Long, val guestId: Long ) 

每次插入新的Reservation ,都必须插入ReservationGuestJoin对象才能实现外键约束。 现在如果你想获得Guest列表,你可以使用SQL查询的强大function:

 @Dao interface ReservationGuestJoinDao { @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) @Query(""" SELECT * FROM guest INNER JOIN reservationGuestJoin ON guest.id = reservationGuestJoin.guestId WHERE reservationGuestJoin.reservationId = :reservationId """) fun getGuestsWithReservationId(reservationId: Long): List } 

要查看更多详细信息,请访问此博客