上篇文章介紹了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
中的關聯關係實踐完了。