本文介紹了我如何通過兒童POJO的屬性來合成ManyToMany POJO?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我有兩個類似的Room實體:
@Entity
public class Teacher implements Serializable {
@PrimaryKey(autoGenerate = true)
public int id;
@ColumnInfo(name = "name")
public String name;
}
@Entity
public class Course implements Serializable {
@PrimaryKey(autoGenerate = true)
public short id;
@ColumnInfo(name = "name")
public String name;
}
.和多對多關系的連接表,如下所示:
@Entity(primaryKeys = {"teacher_id", "course_id"})
public class TeachersCourses implements Serializable {
@ColumnInfo(name = "teacher_id")
public int teacherId;
@ColumnInfo(name = "course_id")
public short courseId;
@ColumnInfo(index = true, name = "course_order")
public short courseOrder;
}
.和一些用于獲取某種類型的復合POJO&QOOT;的復合類:
public class TeacherWithCourses implements Serializable {
@Embedded public Teacher teacher;
@Relation(
parentColumn = "id",
entity = Course.class,
entityColumn = "id",
associateBy = @Junction(
value = TeachersCourses.class,
parentColumn = "teacher_id",
entityColumn = "course_id"
)
)
public List<Courses> courses;
}
.那么,我有這種復合刀(&Q;):
@Dao
public abstract class TeacherWithCoursesDao {
[...]
// XXX This one works as expected
@Transaction
@Query("SELECT * FROM teacher " +
"WHERE id=:teacher_id"
)
public abstract LiveData<List<TeacherWithCourses>> getTeachersByTeacherId(int teacher_id);
// XXX FIXME
// This one succeeds at loading "parents", but each "parent"'s list of "children" is empty
@Transaction
@Query("SELECT * FROM teacher " +
"INNER JOIN teacherscourses AS tc ON teacher.id = tc.teacher_id " +
"INNER JOIN course AS c ON c.id = tc.course_id " +
"WHERE tc.course_id = :course_id " +
"ORDER BY teacher.id ASC, tc.course_order ASC"
)
public abstract LiveData<List<TeacherWithCourses>> getTeachersByCourseId(short course_id);
}
問題的重點是.
工作的那個會按預期返回列表:每個TeacherWithCourses
都有老師和List
課程。第二個并非如此:生成的TeacherWithCourses
對象正確加載了Teacher
屬性,但是List<Courses>
屬性有一個空列表,盡管基于INNER JOINS
的復雜SELECT
查詢按預期篩選。
那么,如何像第一個DAO方法一樣獲取完整的TeacherWithCourses
對象列表,但改為按課程ID進行篩選?
推薦答案
我認為您的問題是由于列名重復,并且基本上房間選擇了不正確的值(我認為它使用最后一個值,因此將使用課程ID列值作為教師ID)。
即查詢(帶有聯接)將由列組成:-
id(教師),
姓名(教師),
教師id,
Course_id,
id(課程),
名稱(課程)
假設您的數據庫中有以下內容:-
并且使用了(LiveData不習慣簡潔方便):-
for(Course c: dao.getAllCourses()) {
for (TeacherWithCourses tbc: dao.getTeachersByCourseId(c.id)) {
Log.d("TEACHER","Teacher is " + tbc.teacher.name + " Courses = " + tbc.courses.size());
for(Course course: tbc.courses) {
Log.d("COURSE"," Course is " + course.name);
}
}
}
然后,結果如您所報告的那樣:-
2021-11-10 15:25:30.994 D/TEACHER: Teacher is Course1 Courses = 0
2021-11-10 15:25:30.996 D/TEACHER: Teacher is Course2 Courses = 0
2021-11-10 15:25:30.999 D/TEACHER: Teacher is Course3 Courses = 0
2021-11-10 15:25:30.999 D/TEACHER: Teacher is Course3 Courses = 0
但是(修復)
如果使用不同的列名,例如:-
@Entity
public class AltCourse implements Serializable {
@PrimaryKey(autoGenerate = true)
public short courseid; //<<<<<<<<<<
@ColumnInfo(name = "coursename") //<<<<<<<<<<
public String coursename; //<<<<<<<<<< doesn't matter
}
添加的數據基本上復制了原始課程(相同的ID#),因此:-
與:-
public class AltTeacherWithCourses implements Serializable {
@Embedded
public Teacher teacher;
@Relation(
parentColumn = "id",
entity = AltCourse.class, //<<<<<<<<<< just to use alternative class
entityColumn = "courseid", //<<<<<<<<<<
associateBy = @Junction(
value = TeachersCourses.class,
parentColumn = "teacher_id",
entityColumn = "course_id"
)
)
public List<AltCourse> courses; //<<<<<<<<<< just to use alternative class
}
請注意,使用教師課程表只是說明鏈接了替代課程(而不是創建altTeacherCourses表)
和:-
@Transaction
@Query("SELECT * FROM teacher " +
"INNER JOIN teacherscourses AS tc ON teacher.id = tc.teacher_id " +
"INNER JOIN altcourse AS c ON c.courseid = tc.course_id " +
"WHERE tc.course_id = :course_id " +
"ORDER BY teacher.id ASC, tc.course_order ASC"
)
public abstract List<AltTeacherWithCourses> getAltTeachersByCourseId(short course_id);
然后:-
for(Course c: dao.getAllCourses()) {
for (AltTeacherWithCourses tbc: dao.getAltTeachersByCourseId(c.id)) {
Log.d("TEACHER","Teacher is " + tbc.teacher.name + " Courses = " + tbc.courses.size());
for(AltCourse course: tbc.courses) {
Log.d("COURSE"," Course is " + course.coursename);
}
}
}
即,當然不使用AltCourse,而是在其他相同的中使用AltCourse,則結果為:-
2021-11-10 15:41:09.223 D/TEACHER: Teacher is Teacher1 Courses = 3
2021-11-10 15:41:09.223 D/COURSE: Course is AltCourse1
2021-11-10 15:41:09.223 D/COURSE: Course is AltCourse2
2021-11-10 15:41:09.223 D/COURSE: Course is AltCourse3
2021-11-10 15:41:09.225 D/TEACHER: Teacher is Teacher1 Courses = 3
2021-11-10 15:41:09.225 D/COURSE: Course is AltCourse1
2021-11-10 15:41:09.225 D/COURSE: Course is AltCourse2
2021-11-10 15:41:09.225 D/COURSE: Course is AltCourse3
2021-11-10 15:41:09.229 D/TEACHER: Teacher is Teacher1 Courses = 3
2021-11-10 15:41:09.229 D/COURSE: Course is AltCourse1
2021-11-10 15:41:09.229 D/COURSE: Course is AltCourse2
2021-11-10 15:41:09.229 D/COURSE: Course is AltCourse3
2021-11-10 15:41:09.230 D/TEACHER: Teacher is Teacher2 Courses = 1
2021-11-10 15:41:09.230 D/COURSE: Course is AltCourse3
因此,解決方案是
-
使用唯一列名,或
使用@Prefix注釋(@Embedded的參數),例如您可以使用
:-
public class TeacherWithCourses implements Serializable {
@Embedded(prefix = "prefix_teacher_") //<<<<<<<<<<
public Teacher teacher;
@Relation(
parentColumn = "prefix_teacher_id", //<<<<<<<<<<
entity = Course.class,
entityColumn = "id",
associateBy = @Junction(
value = TeachersCourses.class,
parentColumn = "teacher_id",
entityColumn = "course_id"
)
)
public List<Course> courses;
}
并使用:-
@Transaction
@Query("SELECT teacher.id AS prefix_teacher_id, teacher.name AS prefix_teacher_name, c.* FROM teacher " +
"INNER JOIN teacherscourses AS tc ON teacher.id = tc.teacher_id " +
"INNER JOIN course AS c ON c.id = tc.course_id " +
"WHERE tc.course_id = :course_id " +
"ORDER BY teacher.id ASC, tc.course_order ASC"
)
public abstract List<TeacherWithCourses> getTeachersByCourseId(short course_id);
但是您還需要使用:-
@Transaction
@Query("SELECT id AS prefix_teacher_id, name as prefix_teacher_name FROM teacher " +
"WHERE id=:teacher_id"
)
public abstract List<TeacherWithCourses> getTeachersByTeacherId(int teacher_id);
其他評論:-
唯一的問題是";ORDER BY&QOOT;語句似乎不會影響此&QOOT;子列表&QOOT;的排序。但該子列表可能會出現新問題。
該問題是由于@Relationship的工作方式造成的。
@Relationship
通過基礎查詢獲取父級的所有@Relation
對象。在檢索子查詢時,不會考慮@查詢中任何不影響所檢索的父級的內容。因此,您無法控制訂單。
也許可以考慮”與教師一起上課”的方法,但這樣您就無法控制教師的順序了。另一種方法是對父項和子項使用@Embedded,但隨后必須處理結果,即每個父項/子項組合的結果。
這篇關于我如何通過兒童POJO的屬性來合成ManyToMany POJO?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,