高级用法-多表查询
ROOM 中不允许类中存在对象的直接引用。主要原因:在客户端查询数据库时会严重影响其性能,会严重阻塞UI线程。具体可以查询下Google官方解释。
针对这样的情况,提出了@Embedded注解 将引用的对象属性全部加载当前表中;也提出@TypeConverter , @TypeConverters注解来将复杂类型转化为ROOM支持的数据类型;也提供了@ForeignKey满足表之间关联查询;@Query 也支持直接填写多表联合查询SQL语句;还提供了@Relation 来解决一对多等查询。
(1)@Embedded使用方法
//定义Book
public class Book {
@NonNull
public String name;
public String publicAddress;
@Override
public String toString(){
return "(name: " + name + ", publicAddress: " + publicAddress + ")";
}
}
//修改Student表
@Entity(tableName = "student_table", foreignKeys = {@ForeignKey(entity = ClassInfo.class, parentColumns = {"class_num"},
childColumns = {"class_num"})})
public class StudentInfo {
@ColumnInfo(name = "student_num")
@PrimaryKey
public int studentNumber;
@NonNull
@ColumnInfo(name = "student_name")
public String studentName;
@ColumnInfo(name = "class_num")
public int classNumber;
@ColumnInfo(name = "student_sex")
@SEX
public String sex;
@Embedded(prefix = "book_")
public Book book;
@Override
public String toString(){
return "(student_number: " + studentNumber + ", student_name: " + studentName + ", student_sex: "
+ sex + ", class_num: " + classNumber + ", book: "+ (book == null ? "null" : book.toString()) + ")";
}
@StringDef({SEX_FEMALE, SEX_MALE})
public @interface SEX{
}
public final static String SEX_MALE = "男";
public final static String SEX_FEMALE = "女";
}
@Database(entities = {StudentInfo.class, ClassInfo.class}, version = 3, exportSchema = true)
public abstract class SchoolDatabase extends RoomDatabase {
public abstract StudentDAO studentDAO();
}
//升级处理
public class DataBaseUtils {
private static volatile SchoolDatabase schoolDatabase;
public static SchoolDatabase getSchoolDatabase(Context context){
if(schoolDatabase == null){
synchronized (SchoolDatabase.class){
schoolDatabase = Room.databaseBuilder(context, SchoolDatabase.class, "school_db")
.addMigrations(new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
String sql = "ALTER TABLE student_table ADD student_sex TEXT";
database.execSQL(sql);
}
}, new Migration(2, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
String sql_name = "ALTER TABLE student_table ADD book_name TEXT";
String sql_public = "ALTER TABLE student_table ADD book_publicAddress TEXT";
database.execSQL(sql_name);
database.execSQL(sql_public);
}
})
.build();
}
}
return schoolDatabase;
}
」
(2)@TypeConveter @TypeConveters使用方法,将复杂类型转为ROOM支持的类型
//定义类型转换规则
public class TypeConverterUtils {
@TypeConverter
public String dateToTimestamp(Date date){
if(date != null)return date.toString();
return null;
}
@TypeConverter
public Date fromTimeStamp(String timeStamp){
if(timeStamp == null)return null;
return new Date(timeStamp);
}
}
//修改表
@Entity(tableName = "student_table", foreignKeys = {@ForeignKey(entity = ClassInfo.class, parentColumns = {"class_num"},
childColumns = {"class_num"})})
public class StudentInfo {
@ColumnInfo(name = "student_num")
@PrimaryKey
public int studentNumber;
@NonNull
@ColumnInfo(name = "student_name")
public String studentName;
@ColumnInfo(name = "class_num")
public int classNumber;
@ColumnInfo(name = "student_sex")
@SEX
public String sex;
@Embedded(prefix = "book_")
public Book book;
@ColumnInfo(name = "birthDay")
public Date date;
@Override
public String toString(){
return "(student_number: " + studentNumber + ", student_name: " + studentName + ", birthDay: " + (date == null ? "unknown" : date.toString()) +", student_sex: "
+ sex + ", class_num: " + classNumber +", book: "+ (book == null ? "null" : book.toString()) + ")";
}
@StringDef({SEX_FEMALE, SEX_MALE})
public @interface SEX{
}
public final static String SEX_MALE = "男";
public final static String SEX_FEMALE = "女";
}
//修改数据库,添加转换规则
@TypeConverters(value = {TypeConverterUtils.class})
@Database(entities = {StudentInfo.class, ClassInfo.class}, version = 4, exportSchema = true)
public abstract class SchoolDatabase extends RoomDatabase {
public abstract StudentDAO studentDAO();
}
public class DataBaseUtils {
private static volatile SchoolDatabase schoolDatabase;
public static SchoolDatabase getSchoolDatabase(Context context){
if(schoolDatabase == null){
synchronized (SchoolDatabase.class){
schoolDatabase = Room.databaseBuilder(context, SchoolDatabase.class, "school_db")
.addMigrations(new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
String sql = "ALTER TABLE student_table ADD student_sex TEXT";
database.execSQL(sql);
}
}, new Migration(2, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
String sql_name = "ALTER TABLE student_table ADD book_name TEXT";
String sql_public = "ALTER TABLE student_table ADD book_publicAddress TEXT";
database.execSQL(sql_name);
database.execSQL(sql_public);
}
}, new Migration(3, 4) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
String sql = "ALTER TABLE student_table ADD birthDay TEXT";
database.execSQL(sql);
}
})
.build();
}
}
return schoolDatabase;
}
}
(3) foreignKey 建立之间关联, quey 进行多表查询
(4)@Relation 是room 指定的一对多,多对多的解决方案。
//一对多,即一个class : n个学生
public class ClassAndStudent {
@ColumnInfo(name = "class_num")
public int classNumber;
@ColumnInfo(name = "class_name")
public String className;
@Relation(parentColumn = "class_num", entityColumn = "class_num")
List<StudentInfo> studentInfos;
}
//访问接口
@Query("SELECT * FROM class_table")
public abstract List<ClassAndStudent> getAll();