Android Room中如何让Machine实体关联并包含MachineType实体?
Hey there! I totally get where you're coming from—you’re used to Spring Boot’s JPA letting you directly embed a related entity via foreign keys, but Room’s behaving differently and it’s frustrating. Let’s walk through exactly how to replicate that "direct entity reference" behavior in Room.
First, we need to add a foreign key column to the Machine entity that links to MachineType. This tells SQLite how the two tables are related, but alone it won’t let you fetch the full MachineType with Machine—we’ll fix that next.
@Entity( foreignKeys = [ForeignKey( entity = MachineType::class, parentColumns = ["id"], childColumns = ["machine_type_id"], onDelete = ForeignKey.CASCADE // Optional: defines behavior if MachineType is deleted )] ) data class Machine( @PrimaryKey val id: Long, val machine_type_id: Long // Foreign key linking to MachineType's id ) @Entity data class MachineType( @PrimaryKey val id: Long // Add any other fields you need here, e.g., name, description )
Room doesn’t let you directly nest entities in each other like JPA does. Instead, we’ll make a separate data class that wraps both Machine and its associated MachineType using Room’s @Embedded and @Relation annotations.
data class MachineWithType( @Embedded val machine: Machine, // Pulls all fields from Machine into this class @Relation( parentColumn = "machine_type_id", // Foreign key in Machine entityColumn = "id" // Primary key in MachineType ) val machineType: MachineType // The related MachineType entity )
Next, update your DAO to return this combined data class. We use @Transaction because Room needs to run two queries (one for Machine, one for the matching MachineType) in a single transaction to keep data consistent.
@Dao interface MachineDao { // Fetch a single machine with its associated type @Transaction @Query("SELECT * FROM Machine WHERE id = :machineId") suspend fun getMachineWithType(machineId: Long): MachineWithType? // Fetch all machines along with their types @Transaction @Query("SELECT * FROM Machine") suspend fun getAllMachinesWithTypes(): List<MachineWithType> }
Now when you fetch data from the DAO, you’ll get a MachineWithType object that contains both the Machine and its full MachineType—exactly like the behavior you’re used to in Spring Boot. Here’s a quick example of how to use this in a REST controller:
@RestController @RequestMapping("/machines") class MachineController( private val machineDao: MachineDao ) { @GetMapping("/{id}") suspend fun getMachine(@PathVariable id: Long): ResponseEntity<MachineWithType> { val machineWithType = machineDao.getMachineWithType(id) return machineWithType?.let { ResponseEntity.ok(it) } ?: ResponseEntity.notFound().build() } }
Room is a lightweight SQLite-based ORM, unlike JPA which handles automatic lazy-loading and entity embedding out of the box. The foreign key only defines the database-level relationship—you need @Relation to tell Room how to fetch and map the related entity alongside the parent.
内容的提问来源于stack exchange,提问作者jared

