Room中关联实体CarOwner的Dao层CRUD操作实现疑问
嗨,我明白你现在遇到的问题了——Room里的关联数据类(像你定义的CarOwner)确实只能用来做查询,不能直接拿来做插入、更新或者删除操作,因为Room的@Insert/@Update/@Delete这些注解只认被@Entity标记的实体类。我来一步步帮你解决各个CRUD场景的实现:
核心原因先理清楚
你定义的CarOwner是查询专用的组合数据类,用@Embedded和@Relation来关联两个实体表的数据,Room只会在查询时自动帮你拼接关联数据,但不会把它当作可操作的实体来处理。所以所有的增删改操作,都需要直接针对CarEntity(因为你的需求里增删改都是围绕车辆数据,车主数据已经提前存在)。
1. Create(插入车辆)
既然你能确保插入车辆时ownerId是有效的,那直接操作CarEntity就好,不需要用到CarOwner:
@Dao interface CarDao { // 插入单辆汽车,返回生成的车辆id @Insert fun insertCar(car: CarEntity): ListenableFuture<Long> }
调用时直接传入构造好的CarEntity实例(记得填好有效的ownerId)就行。
2. Read(查询需求)
你的两个查询需求可以分两种方式实现:
(a) 获取所有车辆的注册号及对应车主姓名
不需要返回完整的CarOwner,可以定义一个更轻量的专用数据类来接收查询结果:
// 专用查询结果类,只包含需要的字段 data class CarRegistrationWithOwner( val registration: String, val ownerName: String ) @Dao interface CarDao { @Query("SELECT c.registration, o.name FROM cars c JOIN owners o ON c.ownerId = o.id") fun getAllCarRegistrationsWithOwners(): ListenableFuture<List<CarRegistrationWithOwner>> }
(b) 获取特定车主的所有车辆注册号
直接通过ownerId查询cars表即可:
@Dao interface CarDao { @Query("SELECT registration FROM cars WHERE ownerId = :ownerId") fun getCarRegistrationsByOwner(ownerId: Long): ListenableFuture<List<String>> }
你原来的find方法是没问题的
你写的根据车辆id查询完整CarOwner的方法是正确的,@Transaction配合@Query+@Relation会自动帮你加载关联的车主数据:
@Dao interface CarDao { @Transaction @Query("SELECT * FROM cars WHERE id = :id") fun find(id: Long): ListenableFuture<CarOwner> }
3. Update(更新车辆信息)
更新车辆的注册号、车主(即ownerId)都只需要操作CarEntity,Room会根据主键id自动更新对应的字段:
@Dao interface CarDao { // 更新车辆信息,返回受影响的行数 @Update fun updateCar(car: CarEntity): ListenableFuture<Int> }
调用时,你只需要构造一个修改了对应字段的CarEntity实例(确保id是正确的),Room就会帮你更新数据库里的记录——不管你只改了注册号、只改了ownerId,还是两个都改了,都能用这个方法。
4. Delete(删除车辆)
删除车辆同样只需要操作CarEntity,如果想根据车辆id删除,可以用@Query更直接:
@Dao interface CarDao { // 根据车辆id删除,返回受影响的行数 @Query("DELETE FROM cars WHERE id = :carId") fun deleteCarById(carId: Long): ListenableFuture<Int> // 或者传入CarEntity实例删除 @Delete fun deleteCar(car: CarEntity): ListenableFuture<Int> }
这两种方式都不会影响owners表的数据,完全符合你“删除车辆但保留车主”的需求。
最后再总结下Dao的完整结构
把上面的方法整合起来,你的CarDao应该是这样的:
@Dao interface CarDao { // Create @Insert fun insertCar(car: CarEntity): ListenableFuture<Long> // Read @Transaction @Query("SELECT * FROM cars WHERE id = :id") fun find(id: Long): ListenableFuture<CarOwner> @Query("SELECT c.registration, o.name FROM cars c JOIN owners o ON c.ownerId = o.id") fun getAllCarRegistrationsWithOwners(): ListenableFuture<List<CarRegistrationWithOwner>> @Query("SELECT registration FROM cars WHERE ownerId = :ownerId") fun getCarRegistrationsByOwner(ownerId: Long): ListenableFuture<List<String>> // Update @Update fun updateCar(car: CarEntity): ListenableFuture<Int> // Delete @Query("DELETE FROM cars WHERE id = :carId") fun deleteCarById(carId: Long): ListenableFuture<Int> }
这样所有的需求都能满足,而且完全遵循Room的设计规范——关联数据类只用于查询,增删改直接操作实体类。
内容来源于stack exchange

