1. 程式人生 > >Android GreenDao3.2表關聯及快取相關

Android GreenDao3.2表關聯及快取相關

最近專案中 使用GreenDao資料庫 遇到了以前沒有踩過的坑:表的一對一 一對多關聯以及快取。

      sqlite資料庫是沒有快取一說的 但是greenDao貌似是有滴 今天捋一捋權當備忘。

      基礎整合的部分及註解解釋部分 直接推薦一片文章就不贅述了【戳我】

      所謂一對一:就是目標實體只對應一個源實體 我們只要操作目標實體就能獲得相應的唯一源實體資訊 目標與源的資訊關聯由greenDao去做了處理

     所謂一對多:就是目標實體對應多個源實體 我們只要操作目標實體就能獲得相應的多個源實體資訊 目標與源的資訊關聯由greenDao去做了處理

 場景描述:

        資料庫中有Teacher表一個,如下:

比較簡單隻有主鍵id和name兩個屬性且name屬性唯一

@Entity
public class Teacher {
    @Id(autoincrement = true)
    private Long id;
@NotNull
    @Unique
private String name;

... ...

}

那麼隨著業務的發展 要給老師們配備女朋友 穩定工作^_^ 在建GirlFriend表一個,如下:

很簡單隻有主鍵id和name兩個屬性,

@Entity
public class GirlFriend {
    @Id(autoincrement = true)
    private 
Long id; private String name;
          ... ...
}

但是一個老師只能有一個女朋友呦 就形成了一對一的關係了

          這個時候就該我們的@ToOne標記出場了給誰標記 怎麼去標呢? 這裡主要是對老師進行操作 那麼老師就是目標實體

          女朋友就是源實體 讓目標實體去關聯源實體 我們給目標實體去新增@ToOne標記就好了 修改下目標實體如下:

@Entity
public class Teacher {
    @Id(autoincrement = true)
    private Long id;
@NotNull
@Unique private String name; private Long g_id; // 關聯兩個表的外來鍵 @ToOne(joinProperty = "g_id") private GirlFriend mGirlFriend; // 源實體
                 
... ...

}

關於joinProperty 在原始碼中的解釋是:

Name of the property inside the current entity which holds the key of related entity. 我的理解是:當前實體(目標實體)的屬性名稱(即g_id)持有相關實體(源實體)的鍵(id,在GirlFriend表中就是主鍵)

Make Project之後我們會發現目標實體多了個關鍵的方法getMGirlFriend()

## 記得升級下資料庫版本號 不然會報錯

/** To-one relationship, resolved on first access. */
@Generated(hash = 400379903)
public GirlFriend getMGirlFriend() {
    Long __key = this.g_id;
if (mGirlFriend__resolvedKey == null
|| !mGirlFriend__resolvedKey.equals(__key)) {
        final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
            throw new DaoException("Entity is detached from DAO context");
}
        GirlFriendDao targetDao = daoSession.getGirlFriendDao();
// 實際上就是拿這個外來鍵g_id 去查了GirlFriend表
GirlFriend mGirlFriendNew = targetDao.load(__key);
synchronized (this) {
            mGirlFriend = mGirlFriendNew;
mGirlFriend__resolvedKey = __key;
}
    }
    return mGirlFriend;
}

這樣基本就形成了老師---女友的一對一關係 。。。等等這還沒完 給老師配備好女友之後記得要更新下老師的資訊 要不然資料庫中不會儲存這個資訊的

// 新增女友
private void addGF(Teacher teacher) {
    // 製造女友
GirlFriend girlFriend = DataUtil.getGirlFriend();
// 插入資料庫
mDaoManager.insertGirlFriend(girlFriend);
// 查詢女友 獲得主鍵id
GirlFriend girlFriend1 = mDaoManager.queryGirlFriend(girlFriend.getName());
// 更新獲得女友的Teacher
mDaoManager.updateTeacher(teacher, girlFriend1.getId());
List<Teacher> list = mDaoManager.queryTeachers(mKey);
// 重新整理頁面
refreshView(list);
}
*************************************************分割線****************************************************************************************

     又過了不久 業務繼續升級 一個老師可以有多個學生 就形成了1對多的關係

先來張學生表,只有主鍵id、name和score分數三個屬性:

@Entity
public class Student {
    @Id(autoincrement = true)
    private Long id;
private String name;
private float score;
... ...
}

 這個時候就該我們的@ToMany標記出場了給誰標記 怎麼去標呢? 這裡是在上面新增女友的基礎上對老師進行操, 那麼老師依然是目標實體,學生是源實體;讓目標實體去關聯源實體 我們給目標實體去新增@ToMany標記同時源實體要新增@ToOne標記與老師對應修改下如下:

首先對源實體做一對一的修改:

@Entity
public class Student {
    @Id(autoincrement = true)
    private Long id;
private String name;
private float score;
private Long t_id;  // 其實就是Teacher的主鍵
    // 這裡老師是源實體
@ToOne(joinProperty = "t_id") //被引用
    private Teacher mTeacher;
... ...
}

Make Project之後我們會發現目標實體多了個關鍵的方法getMTeacher()與一對一的類似就不貼程式碼了^_^

  接下來是目標實體老師的修改:

@Entity
public class Teacher {
    @Id(autoincrement = true)
    private Long id;
@NotNull
    @Unique
private String name;
private Long g_id;  // 關聯兩個表的外來鍵
@ToOne(joinProperty = "g_id")
    private GirlFriend mGirlFriend;  // 源實體
@ToMany(referencedJoinProperty = "t_id") // 與源實體 外來鍵相對應
    private List<Student> mStudents;
... ...

}

 關於referencedJoinProperty 原始碼中是這樣註釋的:

Name of the property inside the target entity which holds id of the source (current) entity 我的理解是:指定目標實體與源實體的相關聯的外來鍵

Make Project之後我們會發現目標實體多了個關鍵的方法getMStudents():

@Generated(hash = 1758362269)
public List<Student> getMStudents() {
    if (mStudents == null) {
        final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
            throw new DaoException("Entity is detached from DAO context");
}
        StudentDao targetDao = daoSession.getStudentDao();
// 其實就查詢學生表將持有相同老師id的學生找出來
List<Student> mStudentsNew = targetDao._queryTeacher_MStudents(id);
synchronized (this) {
            if (mStudents == null) {
                mStudents = mStudentsNew;
}
        }
    }
    return mStudents;
}

檢視targetDao._queryTeacher_MStudents(id) 發現是StudentDao的方法

/** Internal query to resolve the "mStudents" to-many relationship of Teacher. */
public List<Student> _queryTeacher_MStudents(Long t_id) {
    synchronized (this) {
        if (teacher_MStudentsQuery == null) {
            QueryBuilder<Student> queryBuilder = queryBuilder();
queryBuilder.where(Properties.T_id.eq(null));
teacher_MStudentsQuery = queryBuilder.build();
}
    }
    Query<Student> query = teacher_MStudentsQuery.forCurrentThread();
query.setParameter(0, t_id);
return query.list();
}
一目瞭然了!!!!-------別忘記升級資料庫版本號!

這樣老師---學生的一對多關係就有了 。。。但是 在給老師配備好學生之後更新老師的資訊後然並卵並沒有重新整理我的介面 和上面一對一的情況不同啊 為毛 捋了好幾遍流程沒錯啊 懵逼了!! 退出程式重新進 查詢老師的資訊 又顯示剛新增的學生資訊了 試驗了幾次都是這樣 和同事討論下了就懷疑快取的問題 他很肯定sqlite mySqlite什麼的是沒有快取一說的 難道greenDao自帶快取?? 上網查了下還真有 點選開啟連結 具體如下:

 public TeacherDao getTeacherDao() {
        // 去除資料庫快取
mDaoSession.clear();
return mDaoSession.getTeacherDao();
}

其實一對多還有兩種方法 不過我沒有研究就不搬磚了 詳細的請戳我

為什麼一對一的時候沒問題 我也沒有搞懂 有知道的大神歡迎指點!!

還有一個小功能就是查詢Teacher的時候讓學生按分數降序/升序排列

直接上程式碼了

@Entity
public class Teacher {
    @Id(autoincrement = true)
    private Long id;
@NotNull
    @Unique
private String name;
private Long g_id;  // 關聯兩個表的外來鍵
@ToOne(joinProperty = "g_id")
    private GirlFriend mGirlFriend;  // 源實體
@ToMany(referencedJoinProperty = "t_id")
    @OrderBy(value = "score DESC") // 根據分數降序排列
    private List<Student> mStudents;
... ...
}
生成程式碼之後會在StudentDao中發生神奇的改變(紅色標記):
/** Internal query to resolve the "mStudents" to-many relationship of Teacher. */
public List<Student> _queryTeacher_MStudents(Long t_id) {
    synchronized (this) {
        if (teacher_MStudentsQuery == null) {
            QueryBuilder<Student> queryBuilder = queryBuilder();
queryBuilder.where(Properties.T_id.eq(null));
queryBuilder.orderRaw("T.'SCORE' DESC");teacher_MStudentsQuery = queryBuilder.build();
}
    }
    Query<Student> query = teacher_MStudentsQuery.forCurrentThread();
query.setParameter(0, t_id);
return query.list();
}

最後我彥神鎮樓!^_^