標籤:資料庫操作 資料 android 解決 表名
-
-
- 概述
- 悠悠綠水傍林侵日落觀山四望回
- 幽林古寺孤明月冷井寒泉碧映台
- 鷗飛滿浦漁舟泛鶴伴閑亭仙客來
- 遊徑踏花煙上走流溪遠棹一篷開
概述
一個不小心都寫了三篇了,也不知道大家還看得懂不?如果看不懂最好給我留個言,我好下一次改正。
接著上次的說,準備工作都已經做好了,現在咱們就要開始著手解決阻擋Android資料庫操作通用化的五個問題了。
-
我們先回顧一下問題:
-
問題1:表名的擷取
-
問題2:如何將實體中的資料,按照對應關係匯入到資料庫中
-
問題3:明確實體中主鍵是誰?擷取到主鍵中封裝的值
-
問題4:如何將資料庫中表的列的資料,按照對應關係,封裝到實體中
-
問題5:實體的對象建立
悠悠綠水傍林侵,日落觀山四望回。
問題當然是一個一個解決,這樣才有效率,那麼第一個問題來了:表名如何擷取。
通常情況下,解決一個問題時,都會以一個方法或者函數開始,這次也不例外,我們先給一個殼子:
/** 問題一:表名的擷取 **/public String getTableName() { return null;}
一切充滿了希望,也顯得那麼自然。現在我們就要開始思考一些關於如何擷取表名的問題了。
在實際開發中,每一個資料庫表,都會對應著一個具體的實體。就好像news表對應著News類。看看它們,是不是名字好相似?只不過一個是首字母大寫,另一個是全小寫。於是我們心底這麼想,如果我們能夠通過“實體”拿到表名就好了。
既然有了路走走看,就知道走的通還是走不通了。
-
我們可以提出兩個方案:
-
① 如果能夠擷取到實體,那麼我們就能夠擷取到實體的簡單名稱,然後只需要將首字母小寫就是表名了。但是,這樣的缺點也很明顯,這要求資料庫定義表的名稱和實體的名稱基本一致,這樣就會導致我們定義的實體名稱收到限制。例如:定義了
news表,那麼對應的實體就只能是
News了。
-
② 利用註解,這樣就可以讓實體的名稱和資料庫表的名稱之間的關係脫離,兩者互不干涉。缺點也是顯而易見,編碼難度增加,(嘿嘿),不過誰叫咱們是有經驗的開發人員,就選這種了。
如果有同學註解遺忘掉了,或者還不是很清晰,可以參看我的這篇文章:http://blog.csdn.net/biezhihua/article/details/43783165
幽林古寺孤明月,冷井寒泉碧映台。
明確了道路,一路向前就可以了。
接下來就要使用到註解和反射什麼的了!!是不是有點小激動~哈哈~
接下來的任務,就是給News實體類增加一個註解了,增加註解的目的則是,將資料庫表和對應實體之間的關係確定下來。請看代碼:
// 註解的作用:將資料庫表和對應的實體確定下來。@TableName(DBHelper.TABLE_NEWS_NAME)public class News { private int id; private String title; private String summary;}
看起來像模像樣的,但是@TableName(DBHelper.TABLE_NEWS_NAME)這句是什嗎? 誰能告訴我?
這句就是我們寫的註解了,但是,此時我們還沒有建立出來,但是不要緊,如果你使用的是Eclipse,請選中這行Ctrl+1,就可以自動建立了,這麼高大上,是不是被震到了!(^ω^)。請看具體的TableName代碼:
/** * 制定了實體和資料庫中表的對應關係 */@Target(ElementType.TYPE) // 指定放置的位置@Retention(RetentionPolicy.RUNTIME) // 指定存活時間public @interface TableName { /** * 資料庫中的表名,此處可以存放值 */ String value();}
一切都是這麼簡單明了,讓人心曠神怡。現在,註解已經建立好,實體上的註解也已經添加完畢,並且傳入了表名。接下來在getTableName方法中,繼續填寫代碼就好了。
-
擷取表名依舊分為兩步:
-
① 擷取到對象的實體 - 這個是問題五
-
② 擷取實體頭上的註解,依據value的設定值,確定操作的表。
在虛擬碼的第一步是擷取到對象的實體,經過查看,這個恰好是第五個問題,我們先放著,寫一個空方法來代表。
/** * 問題五:實體物件的建立 */private M getInstance() { return null;}
具體的getTableName()方法代碼如下所示:
public String getTableName() { // 虛擬碼: // ① 問題五:擷取到對象的實體 M m = getInstance(); // ② 擷取實體頭上的註解,依據value的設定值,確定操作的資料庫表 // 需要注意的,想要在“運行時”擷取到註解的資訊,給註解設定存活時間。 TableName tableName = m.getClass().getAnnotation(TableName.class); // annotationType 註解的類型 // 為了安全起見,判斷註解的合法性;合法則返回value值 if (tableName != null) { return tableName.value(); } return null;}
有了這個方法,BaseDaoSupport中的delete方法也就可以寫出來了,依舊很簡單,請看代碼:
@Overridepublic int delete(Serializable id) { return db.delete(getTableName(), DBHelper.TABLE_ID + "=?", new String[] { id.toString() });}
小結:其實呢,在表名的擷取中,我們就是利用註解去解決了一個事,表和實體是一一對應的,它們之間的對應關係是什麼。(TableName)
鷗飛滿浦漁舟泛,鶴伴閑亭仙客來。
是時候表演真正的技術了!!(╰_╯)#
接下來該解決第二個問題了,如何將實體中的資料,按照對應關係匯入到資料庫中。
回想一下第一個問題的解決,其實就是利用註解解決了,表和實體之間的對應關係。以此類推,第二個問題也是要求將實體中的資料,按照對應關係匯入到資料庫中。一樣的思路,繼續往下延續,可以再為實體的欄位一個註解,來體現和資料庫表中列的對應關係。請看代碼:
/** * 制定了實體的子對岸和資料庫表中列的對應關係 */@Target(ElementType.FIELD) // 指定放置的位置@Retention(RetentionPolicy.RUNTIME) // 指定存活時間public @interface Column { String value();}
只要欄位上有這個註解的,肯定是和資料庫表中的列有對應關係,接下來為實體的欄位添加相應的註解,並傳入列名。請看代碼:
// 註解的作用:將資料庫表和對應的實體確定下來。@TableName(DBHelper.TABLE_NEWS_NAME)public class News { // 指定了實體和資料庫中表的對應關係 @Column(DBHelper.TABLE_ID) private int id; @Column(DBHelper.TABLE_NEWS_TITLE) private String title; @Column(DBHelper.TABLE_NEWS_SUMMARY) private String summary;}
準備工作已經做好了,接下來就要填寫insert中的代碼了,此處建立了一個fillColumn(M m, ContentValues values)方法,把實體M欄位值和欄位上Column(XXX)註解中傳入的列名,用values.put(key,value)方法填入到valeus中,以便insert中填寫資料。代碼如下:
@Overridepublic long insert(M m) { ContentValues values = new ContentValues(); // m代表資料來源,vlaues是資料匯入的目標 fillColumn(m, values); return db.insert(getTableName(), null, values);}
代碼很簡單,關鍵在於fillColumn(m, values);的資料填充。通過使用反射技術,擷取到M執行個體的所有欄位集合,再依次拿到每個欄位的值和每個欄位註解的值,並填充到values中,請看代碼:
/** * 問題二:如何將實體中的資料,按照對應關係匯入到資料庫中 * * @param m 資料來源 * @param values 是資料匯入的目標 */public void fillColumn(M m, ContentValues values) { // 擷取m上所有的欄位 Field[] fields = m.getClass().getDeclaredFields(); for (Field field : fields) { // 設定存取權限 field.setAccessible(true); // 擷取欄位頭上的註解 Column column = field.getAnnotation(Column.class); if (column != null) { try { String key = column.value(); // 擷取註解中,指定的列名 String value = field.get(m).toString(); // 擷取欄位值 // 填寫資料 values.put(key, value); } catch (IllegalArgumentException e) { throw new RuntimeException("欄位不屬於m執行個體"); } catch (IllegalAccessException e) { throw new RuntimeException("沒有訪問欄位域的許可權"); } } }}
總結:只要掌握了思路和方法,整潔、清晰的代碼,寫起來也不是那麼困難。
遊徑踏花煙上走,流溪遠棹一篷開。
人生不相見,動如參與商.
今夕複何夕,共此燈燭光.
少壯能幾時,鬢髮各已蒼.
訪舊半為鬼,驚呼熱中腸.
焉知二十載,重上君子堂.
昔別君未婚,兒女忽成行……
如何將Android資料庫操作通用化(三)