房间数据库,使用列表构建和查询实体
Room Database, structuring and querying entity with list
这是我的设置。我有一个 WorkoutPlan 对象,其中可以包含一个 Workout 对象列表。我目前对其建模的方式是使用第三个 table 来处理将两者映射在一起。一个锻炼计划可以包含很多锻炼,一个锻炼可以被多个锻炼计划使用。
@Entity(tableName = "workoutPlans")
data class DbWorkoutPlan(@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "date")
val date: Date) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int = 0
}
@Entity(tableName = "workouts")
data class DbWorkout(@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "date")
val data: Date) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int = 0
}
@Entity(tableName = "DbWorkoutPlanWorkoutJoin",
primaryKeys = arrayOf("workoutPlanId", "workoutId"),
foreignKeys = arrayOf(ForeignKey(entity = DbWorkoutPlan::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("workoutPlanId")),
ForeignKey(entity = DbWorkout::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("workoutId"))))
data class DbWorkoutPlanWorkoutJoin(@ColumnInfo(name = "workoutPlanId")
val workoutPlanId: Int,
@ColumnInfo(name = "workoutId")
val workoutId: Int)
这就是我为 table 设置的数据。我不确定它是否正确。在返回的数据方面,我有这个。
data class DbWorkoutPlanResult(@Embedded
val workoutPlan: WorkoutPlan,
@Relation(parentColumn = "id", entityColumn = "workoutId")
val workoutIds: List<DbWorkout>)
所以我想取回一个 DbWorkoutPlanResult,其中包含一个 WorkoutPlan 和它拥有的所有锻炼的列表。
我知道我做的不对,而且复杂性正在迅速增加。有谁知道我在设置中做错了什么?我需要查询什么?我最好的尝试是这个
@Query("SELECT * " +
"FROM DbWorkoutPlanWorkoutJoin " +
"INNER JOIN workoutPlans " +
"ON DbWorkoutPlanWorkoutJoin.workoutPlanId = workoutPlans.id " +
"INNER JOIN workouts " +
"ON DbWorkoutPlanWorkoutJoin.workoutId = workouts.id ")
fun getWorkoutPlans(): Flowable<List<DbWorkoutPlanResult>>
提前致谢。
使用@Relation
注释你可以创建一个1:N(一对多)关系。例如,在您的情况下,一个 计划 可以有多个 锻炼 ,但每个锻炼只能属于一个计划。这显然不是你想要的!
对于您的需求,我假设是这样的:获取包含 plan
的 POJOs
列表和关联的 workouts
列表,您需要使用单独的 JOIN Table(我猜你已经是了)。
获取结果的一种简单方法是将操作分为两个查询:
- 获得所有计划中的
List<DbWorkoutPlan>
个
- 查询 Join Table 并获取所有
List<DbWorkout>
for each DbWorkoutPlan
示例代码
首先定义模型
@Entity(tableName="plans") class DbWorkoutPlan {
@PrimaryKey
private long id;
// ...
@Ignore private List<DbWorkout>; // do not persist this, also create getter/setter for this field
}
@Entity(tableName="workouts") class DbWorkout {
@PrimaryKey
private long id;
// ...
}
@Entity(
tableName="plan_workout_join"
primaryKeys = {"workoutPlanId", "workoutId"},
foreignKeys = {
@ForeignKey(entity = DbWorkoutPlan.class, parentColumns = "id", childColumns = "plan"),
@ForeignKey(entity = DbWorkout.class, parentColumns = "id", childColumns = "workout")
}
) class PlanWorkoutJoin {
private long plan;
private long workout;
}
现在在 DAO
,
@Query("SELECT * FROM plans")
List<DbWorkoutPlan> getAllPlans();
@Query("SELECT * FROM workouts WHERE workouts.id IN (SELECT workout FROM plan_workout_join WHERE plan_workout_join.plan=:plan)")
List<DbWorkout> getWorkoutsForPlan(long plan);
现在可以查询了,
List<DbWorkoutPlan> plans = dao.getAllPlans();
for(DbWorkoutPlan plan : plans){
List<DbWorkout> workouts = dao.getWorkoutsForPlan(plan.getId());
plan.setWorkouts(workouts);
}
// ... continue
P.S。如果你使用 RxJava,你显然需要稍微修改一下,但核心思想保持不变
这是我的设置。我有一个 WorkoutPlan 对象,其中可以包含一个 Workout 对象列表。我目前对其建模的方式是使用第三个 table 来处理将两者映射在一起。一个锻炼计划可以包含很多锻炼,一个锻炼可以被多个锻炼计划使用。
@Entity(tableName = "workoutPlans")
data class DbWorkoutPlan(@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "date")
val date: Date) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int = 0
}
@Entity(tableName = "workouts")
data class DbWorkout(@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "date")
val data: Date) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int = 0
}
@Entity(tableName = "DbWorkoutPlanWorkoutJoin",
primaryKeys = arrayOf("workoutPlanId", "workoutId"),
foreignKeys = arrayOf(ForeignKey(entity = DbWorkoutPlan::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("workoutPlanId")),
ForeignKey(entity = DbWorkout::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("workoutId"))))
data class DbWorkoutPlanWorkoutJoin(@ColumnInfo(name = "workoutPlanId")
val workoutPlanId: Int,
@ColumnInfo(name = "workoutId")
val workoutId: Int)
这就是我为 table 设置的数据。我不确定它是否正确。在返回的数据方面,我有这个。
data class DbWorkoutPlanResult(@Embedded
val workoutPlan: WorkoutPlan,
@Relation(parentColumn = "id", entityColumn = "workoutId")
val workoutIds: List<DbWorkout>)
所以我想取回一个 DbWorkoutPlanResult,其中包含一个 WorkoutPlan 和它拥有的所有锻炼的列表。
我知道我做的不对,而且复杂性正在迅速增加。有谁知道我在设置中做错了什么?我需要查询什么?我最好的尝试是这个
@Query("SELECT * " +
"FROM DbWorkoutPlanWorkoutJoin " +
"INNER JOIN workoutPlans " +
"ON DbWorkoutPlanWorkoutJoin.workoutPlanId = workoutPlans.id " +
"INNER JOIN workouts " +
"ON DbWorkoutPlanWorkoutJoin.workoutId = workouts.id ")
fun getWorkoutPlans(): Flowable<List<DbWorkoutPlanResult>>
提前致谢。
使用@Relation
注释你可以创建一个1:N(一对多)关系。例如,在您的情况下,一个 计划 可以有多个 锻炼 ,但每个锻炼只能属于一个计划。这显然不是你想要的!
对于您的需求,我假设是这样的:获取包含 plan
的 POJOs
列表和关联的 workouts
列表,您需要使用单独的 JOIN Table(我猜你已经是了)。
获取结果的一种简单方法是将操作分为两个查询:
- 获得所有计划中的
List<DbWorkoutPlan>
个 - 查询 Join Table 并获取所有
List<DbWorkout>
for eachDbWorkoutPlan
示例代码
首先定义模型
@Entity(tableName="plans") class DbWorkoutPlan {
@PrimaryKey
private long id;
// ...
@Ignore private List<DbWorkout>; // do not persist this, also create getter/setter for this field
}
@Entity(tableName="workouts") class DbWorkout {
@PrimaryKey
private long id;
// ...
}
@Entity(
tableName="plan_workout_join"
primaryKeys = {"workoutPlanId", "workoutId"},
foreignKeys = {
@ForeignKey(entity = DbWorkoutPlan.class, parentColumns = "id", childColumns = "plan"),
@ForeignKey(entity = DbWorkout.class, parentColumns = "id", childColumns = "workout")
}
) class PlanWorkoutJoin {
private long plan;
private long workout;
}
现在在 DAO
,
@Query("SELECT * FROM plans")
List<DbWorkoutPlan> getAllPlans();
@Query("SELECT * FROM workouts WHERE workouts.id IN (SELECT workout FROM plan_workout_join WHERE plan_workout_join.plan=:plan)")
List<DbWorkout> getWorkoutsForPlan(long plan);
现在可以查询了,
List<DbWorkoutPlan> plans = dao.getAllPlans();
for(DbWorkoutPlan plan : plans){
List<DbWorkout> workouts = dao.getWorkoutsForPlan(plan.getId());
plan.setWorkouts(workouts);
}
// ... continue
P.S。如果你使用 RxJava,你显然需要稍微修改一下,但核心思想保持不变