最近在做项目的时候遇到了一对多的结构数据存储问题。由于前面的是使用的greendao框架,所以就研究了一下这方面的资料。但是网上的都是官网的一些资料。下面我就简单的介绍一下如何使用。由于是demo很简单所以也不放具体的项目了。
第一步建立第一个学生的类为Student。说明一下,这里必须要有主键,如果不是自增长的,那么在创建对象的时候,就需要赋值。 重点说明一下这个TId,这记录那个外键对应的单一的Teacher类的主键的,一定要有,不然找不到对应的关系。同时这里最好加上下面的那个Teacher对象,当然某些场景是可以使用的(非必须)。
@Entity
public class Student {
@Id(autoincrement = true)
private Long id;
private String name;
private Long tId;
@ToOne(joinProperty = "tId")
private Teacher teacher;
}
接下来就是建立对应的Teacher类。这里需要采用ToMany注解,这里的外键就是上面学生类定义的TID。至于为什么要定义成Long,这个理由和主键定义成Long一样的道理。原因是主键自增类型必须是Long(注意是大写的L)
@Entity
public class Teacher {
@Id(autoincrement = true)
private Long id;
private String name;
@ToMany(referencedJoinProperty = "tId")
private List studnets; // not persisted
}
这里需要注意的是,teacher类自动生成提供的getstudents的方法,如果在某些场景下直接使用是会报错的并也没有提供对应的set方法,所以这里最好重新get、set方法。同样的这里存在后面的需要去重复的问题,所以重写相关的equals、hascode方法。
public void addStudent(Student student){
if (studnets == null){
studnets = new ArrayList<>();
}
studnets.add(student);
}
public List getStudens(){
return studnets;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Teacher brandInfo = (Teacher) o;
if (!name.equals(brandInfo.name)) return false;
return name.equals(brandInfo.name);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + name.hashCode();
return result;
}
准备工作到这里就做完了。接下来就是数据处理的部分了。模拟了每个老师有两个学生。这里用两个list集合分别存储对应的学生和老师。需要注意的是,这里的学生的类的TId必须要是老师存储成功的id.所以这里在存储的时候要获取单个的存储ID老师就只能采用了单个插入,而学生则可以最后一期存储。
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "mydb.db", null);
DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDb());
DaoSession daoSession = daoMaster.newSession();
List mutableList = new ArrayList<>();
List studentList = new ArrayList<>();
daoSession.getTeacherDao().deleteAll();
daoSession.getStudentDao().deleteAll();
daoSession.startAsyncSession();
Log.d(TAG, "onCreate: 0");
for (int i = 0;i<10000;i++) {
Teacher teacher = new Teacher();
teacher.setName("zhong"+i);
Long sid =daoSession.getTeacherDao().insertOrReplace(teacher);
for (int j = 0;j<2;j++) {
Student student = new Student();
student.setName( i+ "gua");
teacher.addStudent(student);
student.setTId(sid);
student.setTeacher(teacher);
studentList.add(student);
}
mutableList.add(teacher);
}
daoSession.getStudentDao().insertInTx(studentList);
接下来先看官网的三个例子吧,分别是多表联合、两表联合和自关联查询。
以下是官方实例:涉及三个实例City, Country, and Continent.查询欧洲的所有人数超过一百万的所有城市:
QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000));
Join country = qb.join(Properties.CountryId, Country.class);
Join continent = qb.join(country, CountryDao.Properties.ContinentId, Continent.class, ContinentDao.Properties.Id);
continent.where(ContinentDao.Properties.Name.eq("Europe"));
List bigEuropeanCities = qb.list();
QueryBuilder queryBuilder = userDao.queryBuilder();
queryBuilder.join(Address.class, AddressDao.Properties.userId)
.where(AddressDao.Properties.Street.eq("Sesame Street"));
List users = queryBuilder.list();
QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
由于项目的需求是模糊查询,我这里也采用模糊需求来查询,根据上面的数据查询学生中的名字含有1的所有老师。当然这个实现之后,后面的各种并、或、相等、排序等都是修改某些地方就可以实现,这里就不详细介绍。
第一种实现方式参考官方的例子,两表联合查询。先生成QueryBuilder对象,然后使用关键字join,关联对应表对象和相关的外键。至于join有三种使用方式,详细的介绍可以参考官网,同样的三个例子官网也都有说明,详见http://greenrobot.org/greendao/documentation/joins/。
QueryBuilder queryBuilder = daoSession.getTeacherDao().queryBuilder();
queryBuilder.join(Student.class, StudentDao.Properties.TId)
.where(StudentDao.Properties.Name.like ("%1%"));
// queryBuilder.where(TeacherDao.Properties.Name.like("%11%"));
List querytechers= queryBuilder.list();
第二种实现方式,不使用多表关联使用单表的查询。先找到对应的学生类,然后再遍历通过上面的getTeacher方法找到对应的老师对象集合。
List students= daoSession.getStudentDao().queryBuilder().where(StudentDao.Properties.Name.like("%1%")).list();
List querytechers= getTeacher(students);
private List getTeacher(List students) {
List teachers= new ArrayList<>();
for (int i = 0; i < students.size(); i++) {
teachers.add(students.get(i).getTeacher());
}
return teachers;
}
当然如果处理的数据场景简单,其实不用使用多表,就在字段中添加分隔符存储,后面再对查询的数据做处理。
当然这里还有个问题就是会出现查询的数据有重复,所以这里需要去重,由于某些场景是需要保持顺序的,所以 就采用了保持顺序的去重方法。
private static void DuplicateRemoval(List ioList)
{
LinkedHashSet tmpSet = new LinkedHashSet(ioList.size());
tmpSet.addAll(ioList);
ioList.clear();
ioList.addAll(tmpSet);
}
以上就是多表联合查询的一些小小总结,希望能够对读者有所帮助。