上篇文章介绍了GreenDao
的基本用法,如果你想了解GreenDao
和它的基本用法,建议读下我的这篇文章《Android开源数据库 GreenDao实践》。
相信大家看了标题就知道本文要介绍的内容了,没错,就是GreenDao
对象数据表之间的关联关系,表之间的关联关系:1:1关联、1:N关联,N:M关联。
1:1关联
1:1关联:在A表中定义一个外键去关联B表,查询时通过A表中的外键就可以查询B表中的数据。
那么在GreenDao
中如何实现1:1关联呢?接下来带大家实践一番。
person类:
@Entity
public class Person {
@Id(autoincrement = true)
private Long pid;
private String name;
private int age;
@Generated(hash = 2077399018)
public Person(Long pid, String name, int age) {
this.pid = pid;
this.name = name;
this.age = age;
}
@Generated(hash = 1024547259)
public Person() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Long getPid() {
return pid;
}
public String getName() {
return name;
}
public void setPid(Long pid) {
this.pid = pid;
}
public void setName(String name) {
this.name = name;
}
}
复制代码
这是Person
类,GreenDao
会帮助生成一张对应的表,主键为pid
。
IDCard类:
@Entity
public class IDCard {
@Id(autoincrement = true)
private Long cid;
private Long pid;
//idcard和person是一对一关系,外键为personId
@ToOne(joinProperty = "pid")
private Person mPerson;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1613157014)
private transient IDCardDao myDao;
@Generated(hash = 2035083577)
public IDCard(Long cid, Long pid) {
this.cid = cid;
this.pid = pid;
}
@Generated(hash = 1276747893)
public IDCard() {
}
@Generated(hash = 1159219905)
private transient Long mPerson__resolvedKey;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public Long getCid() {
return cid;
}
public Person getPerson() {
return mPerson;
}
public void setCid(Long cid) {
this.cid = cid;
}
public void setPerson(Person person) {
mPerson = person;
}
/** To-one relationship, resolved on first access. */
@Generated(hash = 780901277)
public Person getMPerson() {
Long __key = this.pid;
if (mPerson__resolvedKey == null || !mPerson__resolvedKey.equals(__key)) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
PersonDao targetDao = daoSession.getPersonDao();
Person mPersonNew = targetDao.load(__key);
synchronized (this) {
mPerson = mPersonNew;
mPerson__resolvedKey = __key;
}
}
return mPerson;
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 153445049)
public void setMPerson(Person mPerson) {
synchronized (this) {
this.mPerson = mPerson;
pid = mPerson == null ? null : mPerson.getPid();
mPerson__resolvedKey = pid;
}
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1719686375)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getIDCardDao() : null;
}
}
复制代码
同样GreenDao
会生成一张对应的IDCard
表。这里,每个人仅有一张IDCard,所以Person
和IDCard
是一对一关联。这里通过pid
作为IDCard
外键关联Person
,还需要使用@ToOne(joinProperty = "pid")
注解,才能关联上。
现在表之间的1:1关系已经关联上了,接下来看下如何使用。
看下简单的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
tools:context="com.lwj.uiproject.RelaActivity">
<Button
android:id="@+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="add"/>
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="update"/>
<Button
android:id="@+id/select"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="select"/>
<Button
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="delete"/>
</LinearLayout>
复制代码
四个按钮,分别对应增删改查.
Activity:
//greenDao一对一关系实践
public class RelaActivity extends AppCompatActivity {
private Button mAdd;
private Button mSelect;
private Button mUpdate;
private Button mDelete;
private PersonDao mPersonDao;
private IDCardDao mIDCardDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rela);
mAdd = (Button)this.findViewById(R.id.add);
mSelect = (Button)this.findViewById(R.id.select);
mUpdate = (Button)this.findViewById(R.id.update);
mDelete = (Button)this.findViewById(R.id.delete);
//设置点击事件
mAdd.setOnClickListener(mOnClickListener);
mSelect.setOnClickListener(mOnClickListener);
mUpdate.setOnClickListener(mOnClickListener);
mDelete.setOnClickListener(mOnClickListener);
mPersonDao = GreenDaoManager.getInstance().getDaoSession().getPersonDao();
mIDCardDao = GreenDaoManager.getInstance().getDaoSession().getIDCardDao();
}
/**
* 点击监听器
*/
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v == mAdd){//添加数据
addData();
}else if (v == mSelect){//查询数据
select(0);
}else if (v == mUpdate){//更改数据
select(1);
}else if (v == mDelete){//删除数据
select(2);
}
}
};
/**
* 往表中插入数据
*/
private void addData() {
try {
Long pid = 1L;//personId
Long cid = 2L;//idcardid;
Person p = new Person(pid, "xiaoMing", 18);
mPersonDao.insert(p);
IDCard c = new IDCard(cid, pid);
c.setPerson(p);
mIDCardDao.insert(c);
Log.i("tag","插入成功");
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","插入失败");
}
}
/**
* 查询idcard表中数据
*/
private void select(int position) {
try {
List<IDCard> list = mIDCardDao.loadAll();//获取idcard表中所有数据
IDCard card = list.get(0);//拿list集合第一条数据
if (card != null){
Log.i("tag","cardid---------->"+card.getCid());
Log.i("tag","personid---------->"+card.getPid());
}
switch (position){
case 0:
selectPersonInfoByCard(card);//根据idcard获取person
break;
case 1:
update(card);
break;
case 2:
delete(card);
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","----获取idcard信息失败------");
}
}
/**
* 删除信息
* @param card
*/
private void delete(IDCard card) {
try {
Person person = null;
if (card != null){
person = card.getPerson();
}
mPersonDao.delete(person);
mIDCardDao.delete(card);
Log.i("tag","----删除信息成功------");
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","----删除信息失败------");
}
}
/***
* 修改person信息
* @param card
*/
private void update(IDCard card) {
try {
Person person = null;
if (card != null){
person = card.getPerson();
}
person.setName("xiaofang");
mPersonDao.update(person);
Log.i("tag","----修改person信息成功------");
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","----修改person信息失败------");
}
}
/**
* 根据IDCard获取得到person信息
* @param card
*/
private void selectPersonInfoByCard(IDCard card) {
Person person = null;
if (card != null){
person = card.getPerson();
}
if (person != null){
Log.i("tag","name---------->"+person.getName());
Log.i("tag","personId---------->"+person.getPid());
Log.i("tag","age---------->"+person.getAge());
}else{
Log.i("tag","----获取person信息失败------");
}
}
}
复制代码
这里的使用跟上一篇文章介绍的没有多大的却别,都是使用GreenDao
里面的增删改查
函数来操作数据库。
因为我是使用上一篇文章的demo基础上增加表的,所以需要在app的build.gradle
下修改数据库版本号schemaVersion
,这里我写为2
,也就是第二版本。
添加数据:
查询数据:
修改数据:
删除数据:
1: N关联
设计:一个老师对应多个学生,那么教师表对应学生表就是1:N关联关系了。在GreenDao
中使用@ToMany
来实现这一关联。
@Entity
public class MStudent {
@Id(autoincrement = true)
private Long sid;
private String name;
private Long tid;
@Generated(hash = 454159030)
public MStudent(Long sid, String name, Long tid) {
this.sid = sid;
this.name = name;
this.tid = tid;
}
@Generated(hash = 1602395591)
public MStudent() {
}
public Long getSid() {
return this.sid;
}
public void setSid(Long sid) {
this.sid = sid;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Long getTid() {
return this.tid;
}
public void setTid(Long tid) {
this.tid = tid;
}
}
复制代码
tid
作为MStudent
表的外键。
@Entity
public class MTecher {
@Id(autoincrement = true)
private Long tid;
private String name;
//一对多关系,tid为Student表的外键
@ToMany(referencedJoinProperty = "tid")
private List<MStudent> students;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1767473471)
private transient MTecherDao myDao;
@Generated(hash = 799726702)
public MTecher(Long tid, String name) {
this.tid = tid;
this.name = name;
}
@Generated(hash = 1508526)
public MTecher() {
}
public Long getTid() {
return this.tid;
}
public void setTid(Long tid) {
this.tid = tid;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
/**
* To-many relationship, resolved on first access (and after reset).
* Changes to to-many relations are not persisted, make changes to the target entity.
*/
@Generated(hash = 558837386)
public List<MStudent> getStudents() {
if (students == null) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
MStudentDao targetDao = daoSession.getMStudentDao();
List<MStudent> studentsNew = targetDao._queryMTecher_Students(tid);
synchronized (this) {
if (students == null) {
students = studentsNew;
}
}
}
return students;
}
/** Resets a to-many relationship, making the next get call to query for a fresh result. */
@Generated(hash = 238993120)
public synchronized void resetStudents() {
students = null;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 690999693)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getMTecherDao() : null;
}
}
复制代码
实现1:N关联最重要的一点就是
//一对多关系,tid为Student表的外键
@ToMany(referencedJoinProperty = "tid")
private List<MStudent> students;
复制代码
而tid
就是刚刚在MStudent
中的tid
。这样就可以把MTecher
和MTecher
的1: N关系关联上了。
使用:
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
tools:context="com.lwj.uiproject.ToManyRelaActivity">
<Button
android:id="@+id/add_teacher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="addTeacher"/>
<Button
android:id="@+id/add_student"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="addStudent"/>
<Button
android:id="@+id/select_s"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="select"/>
</LinearLayout>
复制代码
布局中主要是添加和查询按钮。
public class ToManyRelaActivity extends AppCompatActivity {
private Button mAddTeacher;
private Button mAddStudent;
private Button mSelect;
private MStudentDao mStudentDao;
private MTecherDao mTecherDao;
private Long tid = 1L;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_to_many_rela);
mAddTeacher = (Button)this.findViewById(R.id.add_teacher);
mAddStudent = (Button)this.findViewById(R.id.add_student);
mSelect = (Button)this.findViewById(R.id.select_s);
//设置点击事件
mAddTeacher.setOnClickListener(mOnClickListener);
mAddStudent.setOnClickListener(mOnClickListener);
mSelect.setOnClickListener(mOnClickListener);
mStudentDao = GreenDaoManager.getInstance().getDaoSession().getMStudentDao();
mTecherDao = GreenDaoManager.getInstance().getDaoSession().getMTecherDao();
}
/**
* 点击监听器
*/
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v == mAddStudent){//添加Student数据
insertStudent();
} else if (v == mAddTeacher) {//添加Teacher数据
insertTeacher();
} else if (v == mSelect) {//查询数据
selectTeacher();
}
}
};
/**
* 添加Teacher信息
*/
private void insertTeacher() {
try {
String name = "Miss zhang";
MTecher mTecher = new MTecher(tid, name);
mTecherDao.insert(mTecher);
Log.i("tag","教师信息添加成功");
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","教师信息添加失败");
}
}
/**
* 添加Student信息
*/
private void insertStudent() {
try {
Long sid = 1L;
for (int i = 0; i < 5; i++) {
MStudent s = new MStudent(sid, "xiaoMing-->"+i, tid);
mStudentDao.insert(s);
sid++;
}
Log.i("tag","学生信息添加成功");
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","学生信息添加失败");
}
}
/**
* 查询老师的信息
*/
private void selectTeacher() {
MTecher t = null;
try {
t = mTecherDao.loadByRowId(tid);
if (t != null){
Log.i("tag","查询教师信息---->成功");
Log.i("tag","tid--->"+t.getTid());
Log.i("tag","teacher's name----->"+t.getName());
selectStudentByTeacher(t);
}else{
Log.i("tag","查询表中没有该教师信息");
}
} catch (Exception e) {
e.printStackTrace();
Log.i("tag","查询教师信息---->失败");
}
}
/**
* 根据获取得到的Teacher获取其名下的学生信息
* @param t
*/
private void selectStudentByTeacher(MTecher t) {
List<MStudent> list = t.getStudents();
if (list != null && list.size() > 0){
for (MStudent mStudent : list) {
Log.i("tag","sid--------->"+mStudent.getSid());
Log.i("tag","tid--------->"+mStudent.getTid());
Log.i("tag","name-------->"+mStudent.getName());
}
}else{
Log.i("tag","--------获取学生信息失败--------");
}
}
}
复制代码
这里的查询非常方便,查询到Teacher
信息,直接通过getStudents
就可以获取到到该Teacher
对应的所有同学。
添加Teacher信息:
为刚刚添加的teacher,添加学生信息:
查询信息:
可以看到已经成功获取到信息了。
N:M关联
一个老师可以有多个学生,一个学生也可以有多个老师,这种就是N:M关联。那么在GreenDao
中如何表示这种关系呢?
这就需要一张中间表来实现了,提供一张中间表:存储学生id和老师id即可。学过数据库设计的读者应该非常明白其中的关系。
NStudent:
@Entity
public class NStudent {
@Id(autoincrement = true)
private Long sid;
private String name;
}
复制代码
中间表TandSRelative
:
@Entity
public class TandSRelative {
@Id(autoincrement = true)
private Long tsid;
private Long tid;//teacher的id
private Long sid;//student的id
}
复制代码
NTeacher:
@Entity
public class NTeacher {
@Id(autoincrement = true)
private Long tid;
private String name;
@ToMany
@JoinEntity(entity = TandSRelative.class,sourceProperty = "tid",targetProperty = "sid")
private List<TandSRelative> list;
}
复制代码
主要实现是使用@ToMany
和@JoinEntity
。
至此,已经GreenDao
中的关联关系实践完了。