上一篇已經對ORMLite框架做了簡單的介紹:Android ORMLite 框架的入門用法~~本篇將介紹專案可能會使用到的一些用法,也為我們的使用ORMLite框架總結出一個較合理的用法。
通過上一篇的瞭解,我們使用ORMLite,需要自己寫一個DatabaseHelper去繼承OrmLiteSqliteOpenHelper,下面我們首先給出一個我認為比較靠譜的Helper的寫法:
1、DatabaseHelper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
package com.zhy.zhy_ormlite.db; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; import com.zhy.zhy_ormlite.bean.Article; import com.zhy.zhy_ormlite.bean.Student; import com.zhy.zhy_ormlite.bean.User; public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final String TABLE_NAME = "sqlite-test.db"; private Map<String, Dao> daos = new HashMap<String, Dao>(); private DatabaseHelper(Context context) { super(context, TABLE_NAME, null, 4); } @Override public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) { try { TableUtils.createTable(connectionSource, User.class); TableUtils.createTable(connectionSource, Article.class); TableUtils.createTable(connectionSource, Student.class); } catch (SQLException e) { e.printStackTrace(); } } @Override public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) { try { TableUtils.dropTable(connectionSource, User.class, true); TableUtils.dropTable(connectionSource, Article.class, true); TableUtils.dropTable(connectionSource, Student.class, true); onCreate(database, connectionSource); } catch (SQLException e) { e.printStackTrace(); } } private static DatabaseHelper instance; /** * 單例獲取該Helper * * @param context * @return */ public static synchronized DatabaseHelper getHelper(Context context) { context = context.getApplicationContext(); if (instance == null) { synchronized (DatabaseHelper.class) { if (instance == null) instance = new DatabaseHelper(context); } } return instance; } public synchronized Dao getDao(Class clazz) throws SQLException { Dao dao = null; String className = clazz.getSimpleName(); if (daos.containsKey(className)) { dao = daos.get(className); } if (dao == null) { dao = super.getDao(clazz); daos.put(className, dao); } return dao; } /** * 釋放資源 */ @Override public void close() { super.close(); for (String key : daos.keySet()) { Dao dao = daos.get(key); dao = null; } } } |
1、整個DatabaseHelper使用單例只對外公佈出一個物件,保證app中只存在一個SQLite Connection , 參考文章:http://www.touchlab.co/2011/10/single-sqlite-connection/
2、我們對每個Bean建立一個XXXDao來處理當前Bean的資料庫操作,當然真正去和資料庫打交道的物件,通過上面程式碼中的getDao(T t)進行獲取
getDao為一個泛型方法,會根據傳入Class物件進行建立Dao,並且使用一個Map來保持所有的Dao物件,只有第一次呼叫時才會去呼叫底層的getDao()。
2、Bean的Dao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package com.zhy.zhy_ormlite.db; import java.sql.SQLException; import android.content.Context; import com.j256.ormlite.dao.Dao; import com.zhy.zhy_ormlite.bean.User; public class UserDao { private Context context; private Dao<User, Integer> userDaoOpe; private DatabaseHelper helper; public UserDao(Context context) { this.context = context; try { helper = DatabaseHelper.getHelper(context); userDaoOpe = helper.getDao(User.class); } catch (SQLException e) { e.printStackTrace(); } } /** * 增加一個使用者 * @param user */ public void add(User user) { try { userDaoOpe.create(user); } catch (SQLException e) { e.printStackTrace(); } }//...other operations } |
我們的所有的XXXDao遵循以上的風格~
好了,基本瞭解了我們的程式碼的結構~~ps:如果覺得不合理可以留言指出,如果覺得不能接收,直接忽略。。。
3、ORMLite外來鍵引用
現在我們有兩張表一張User,一張Article;
Article中當然需要儲存User的主鍵,作為關聯~~那麼在ORMLite中如何做到呢?
可能有人會直接在Article中宣告一個int型別userId屬性,當作普通屬性處理搞定,這種做法並沒有做,但是沒有體現出物件導向的思想。
物件導向是這樣的:Article屬於某個User
類這麼定義:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
package com.zhy.zhy_ormlite.bean; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @DatabaseTable(tableName = "tb_article") public class Article { @DatabaseField(generatedId = true) private int id; @DatabaseField private String title; @DatabaseField(canBeNull = true, foreign = true, columnName = "user_id") private User user; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Article [id=" + id + ", title=" + title + ", user=" + user + "]"; } } |
不會去定義一個int型別的userId,而是直接定義一個User成員變數,表示本Article屬於該User;
然後在User user屬性上新增: @DatabaseField(canBeNull = true, foreign = true, columnName = “user_id”)
canBeNull -表示不能為null;foreign=true表示是一個外來鍵;columnName 列名
User類暫且就兩個屬性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package com.zhy.zhy_ormlite.bean; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @DatabaseTable(tableName = "tb_user") public class User { @DatabaseField(generatedId = true) private int id; @DatabaseField(columnName = "name") private String name; public User() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } } |
現在看我們的ArticleDao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
package com.zhy.zhy_ormlite.db; import java.sql.SQLException; import java.util.List; import android.content.Context; import com.j256.ormlite.dao.Dao; import com.zhy.zhy_ormlite.bean.Article; import com.zhy.zhy_ormlite.bean.User; public class ArticleDao { private Dao<Article, Integer> articleDaoOpe; private DatabaseHelper helper; @SuppressWarnings("unchecked") public ArticleDao(Context context) { try { helper = DatabaseHelper.getHelper(context); articleDaoOpe = helper.getDao(Article.class); } catch (SQLException e) { e.printStackTrace(); } } /** * 新增一個Article * @param article */ public void add(Article article) { try { articleDaoOpe.create(article); } catch (SQLException e) { e.printStackTrace(); } } /** * 通過Id得到一個Article * @param id * @return */ @SuppressWarnings("unchecked") public Article getArticleWithUser(int id) { Article article = null; try { article = articleDaoOpe.queryForId(id); helper.getDao(User.class).refresh(article.getUser()); } catch (SQLException e) { e.printStackTrace(); } return article; } /** * 通過Id得到一篇文章 * @param id * @return */ public Article get(int id) { Article article = null; try { article = articleDaoOpe.queryForId(id); } catch (SQLException e) { e.printStackTrace(); } return article; } /** * 通過UserId獲取所有的文章 * @param userId * @return */ public List<Article> listByUserId(int userId) { try { return articleDaoOpe.queryBuilder().where().eq("user_id", userId) .query(); } catch (SQLException e) { e.printStackTrace(); } return null; } } |
接下來看我們的測試類:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class OrmLiteDbTest extends AndroidTestCase { public void testAddArticle() { User u = new User(); u.setName("張鴻洋"); new UserDao(getContext()).add(u); Article article = new Article(); article.setTitle("ORMLite的使用"); article.setUser(u); new ArticleDao(getContext()).add(article); } public void testGetArticleById() { Article article = new ArticleDao(getContext()).get(1); L.e(article.getUser() + " , " + article.getTitle()); } public void testGetArticleWithUser() { Article article = new ArticleDao(getContext()).getArticleWithUser(1); L.e(article.getUser() + " , " + article.getTitle()); } public void testListArticlesByUserId() { List<Article> articles = new ArticleDao(getContext()).listByUserId(1); L.e(articles.toString()); } |
分別測試,新增一個Article;通過Id獲取一個Article;通過Id獲取一個Article且攜帶User;通過userId獲取所有的Article;
主要看第三個:通過Id獲取一個Article且攜帶User,testGetArticleWithUser(id)
如何值傳一個Article的Id,然後能夠拿到Article物件,且內部的user屬性直接賦值呢?
兩種方式:
1、即上述寫法
1 2 |
article = articleDaoOpe.queryForId(id); helper.getDao(User.class).refresh(article.getUser()); |
2、在user屬性的註解上:@DatabaseField(canBeNull = true, foreign = true, columnName = “user_id”, foreignAutoRefresh = true)
新增foreignAutoRefresh =true,這樣;當呼叫queryForId時,拿到Article物件則直接攜帶了user;
4、關聯一個集合
每個User關聯一個或多個Article,如果我在User中宣告一個Collection<Article> articles,我能否在查詢User的時候,一併能夠獲取到articles的值呢?
答案是可以的。在User中新增如下屬性,且註解如下:
@ForeignCollectionField
private Collection<Article> articles;
我們在UserDao中書寫查詢User的程式碼:
1 2 3 4 5 6 7 8 9 10 11 |
public User get(int id) { try { return userDaoOpe.queryForId(id); } catch (SQLException e) { e.printStackTrace(); } return null ; } |
測試程式碼:
1 2 3 4 5 6 7 8 9 10 |
public void testGetUserById() { User user = new UserDao(getContext()).get(1); L.e(user.getName()); if (user.getArticles() != null) for (Article article : user.getArticles()) { L.e(article.toString()); } } |
輸出:
1 2 |
09-07 22:49:06.484: E/zhy(7293): 張鴻洋 09-07 22:49:06.484: E/zhy(7293): Article [id=1, title=ORMLite的使用] |
可以看到,我們通過一個queryForId,成功的獲取了User,以及User關聯的所有的Articles;
5、條件查詢QueryBuilder的使用
上述程式碼其實已經用到了簡單的條件查詢了:
1、簡單的where等於
articleDaoOpe.queryBuilder().where().eq(“user_id”, userId).query();直接返回Article的列表
2、where and
1 2 3 4 5 6 7 8 9 10 11 12 |
QueryBuilder<Article, Integer> queryBuilder = articleDaoOpe .queryBuilder(); Where<Article, Integer> where = queryBuilder.where(); where.eq("user_id", 1); where.and(); where.eq("name", "xxx"); //或者 articleDaoOpe.queryBuilder().// where().// eq("user_id", 1).and().// eq("name", "xxx"); |
上述兩種都相當與:select * from tb_article where user_id = 1 and name = ‘xxx’ ;
3、更復雜的查詢
1 2 3 4 5 6 |
where.or( // where.and(// where.eq("user_id", 1), where.eq("name", "xxx")), where.and(// where.eq("user_id", 2), where.eq("name", "yyy"))); |
select * from tb_article where ( user_id = 1 and name = ‘xxx’ ) or ( user_id = 2 and name = ‘yyy’ ) ;
好了,再複雜的查詢估計也能夠湊出來了~~
6、updateBuilder、deleteBuilder
使用queryBuilder是因為我們希望執行完成查詢直接返回List<Bean>集合;
對於Update我們並不關注返回值,直接使用
articleDaoOpe.updateRaw(statement, arguments);傳入sql和引數即可~~
何必在那articleDaoOpe.updateBuilder().updateColumnValue(“name”,”zzz”).where().eq(“user_id”, 1);這樣的痛苦呢~~~
同理還有deleteBuilder還是建議直接拼寫sql,當然很簡單的除外,直接使用它的API~
7、事務操作
在我們的Dao中直接寫如下程式碼:
1 2 3 4 5 6 7 8 9 10 11 |
//事務操作 TransactionManager.callInTransaction(helper.getConnectionSource(), new Callable<Void>() { @Override public Void call() throws Exception { return null; } }); |
8、其他操作
1、當Bean繼承BaseDaoEnabled時,可以使用bean.create(bean);bean.update(bean)一類操作
例如:
1 2 3 4 5 6 7 |
Student extends BaseDaoEnabled<Student, Integer> Dao dao = DatabaseHelper.getHelper(getContext()).getDao(Student.class); Student student = new Student(); student.setDao(dao); student.setName("張鴻洋"); student.create(); |
前提dao需要手動設定,如果dao為null會報錯,尼瑪,我覺得一點用沒有。。。
2、Join
1 2 3 4 |
QueryBuilder<Article, Integer> articleBuilder = articleDaoOpe .queryBuilder(); QueryBuilder userBuilder = helper.getDao(User.class).queryBuilder(); articleBuilder.join(userBuilder); |
Article與User做Join操作;
本篇主要想介紹在專案中如何寫DataBaseHelper已經如何寫BeanDao,以及列出了在專案中可能會用到的ORMLite的功能,如果需要詳細瞭解,還請看ORMLite官方文件,原始碼中也會提供~~