Android 快速开发系列 ORMLite 框架最佳实践


上一篇已经对ORMLite框架做了简单的介绍:Android ORMLite 框架的入门用法~~本篇将介绍项目可能会使用到的一些用法,也为我们的使用ORMLite框架总结出一个较合理的用法。

通过上一篇的了解,我们使用ORMLite,需要自己写一个DatabaseHelper去继承OrmLiteSqliteOpenHelper,下面我们首先给出一个我认为比较靠谱的Helper的写法:

1、DatabaseHelper

[java]  view plain copy
  1. package com.zhy.zhy_ormlite.db;  
  2.   
  3. import java.sql.SQLException;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. import android.content.Context;  
  8. import android.database.sqlite.SQLiteDatabase;  
  9.   
  10. import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;  
  11. import com.j256.ormlite.dao.Dao;  
  12. import com.j256.ormlite.support.ConnectionSource;  
  13. import com.j256.ormlite.table.TableUtils;  
  14. import com.zhy.zhy_ormlite.bean.Article;  
  15. import com.zhy.zhy_ormlite.bean.Student;  
  16. import com.zhy.zhy_ormlite.bean.User;  
  17.   
  18. public  class DatabaseHelper extends OrmLiteSqliteOpenHelper  
  19. {  
  20.     private static final String TABLE_NAME = "sqlite-test.db";  
  21.   
  22.     private Map<String, Dao> daos = new HashMap<String, Dao>();  
  23.   
  24.     private DatabaseHelper(Context context)  
  25.     {  
  26.         super(context, TABLE_NAME, null4);  
  27.     }  
  28.   
  29.     @Override  
  30.     public void onCreate(SQLiteDatabase database,  
  31.             ConnectionSource connectionSource)  
  32.     {  
  33.         try  
  34.         {  
  35.             TableUtils.createTable(connectionSource, User.class);  
  36.             TableUtils.createTable(connectionSource, Article.class);  
  37.             TableUtils.createTable(connectionSource, Student.class);  
  38.         } catch (SQLException e)  
  39.         {  
  40.             e.printStackTrace();  
  41.         }  
  42.     }  
  43.   
  44.     @Override  
  45.     public void onUpgrade(SQLiteDatabase database,  
  46.             ConnectionSource connectionSource, int oldVersion, int newVersion)  
  47.     {  
  48.         try  
  49.         {  
  50.             TableUtils.dropTable(connectionSource, User.classtrue);  
  51.             TableUtils.dropTable(connectionSource, Article.classtrue);  
  52.             TableUtils.dropTable(connectionSource, Student.classtrue);  
  53.             onCreate(database, connectionSource);  
  54.         } catch (SQLException e)  
  55.         {  
  56.             e.printStackTrace();  
  57.         }  
  58.     }  
  59.   
  60.     private static DatabaseHelper instance;  
  61.   
  62.     /** 
  63.      * 单例获取该Helper 
  64.      *  
  65.      * @param context 
  66.      * @return 
  67.      */  
  68.     public static synchronized DatabaseHelper getHelper(Context context)  
  69.     {  
  70.         context = context.getApplicationContext();  
  71.         if (instance == null)  
  72.         {  
  73.             synchronized (DatabaseHelper.class)  
  74.             {  
  75.                 if (instance == null)  
  76.                     instance = new DatabaseHelper(context);  
  77.             }  
  78.         }  
  79.   
  80.         return instance;  
  81.     }  
  82.   
  83.     public synchronized Dao getDao(Class clazz) throws SQLException  
  84.     {  
  85.         Dao dao = null;  
  86.         String className = clazz.getSimpleName();  
  87.   
  88.         if (daos.containsKey(className))  
  89.         {  
  90.             dao = daos.get(className);  
  91.         }  
  92.         if (dao == null)  
  93.         {  
  94.             dao = super.getDao(clazz);  
  95.             daos.put(className, dao);  
  96.         }  
  97.         return dao;  
  98.     }  
  99.   
  100.     /** 
  101.      * 释放资源 
  102.      */  
  103.     @Override  
  104.     public void close()  
  105.     {  
  106.         super.close();  
  107.   
  108.         for (String key : daos.keySet())  
  109.         {  
  110.             Dao dao = daos.get(key);  
  111.             dao = null;  
  112.         }  
  113.     }  
  114.   
  115. }  

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

[java]  view plain copy
  1. package com.zhy.zhy_ormlite.db;  
  2.   
  3. import java.sql.SQLException;  
  4.   
  5. import android.content.Context;  
  6.   
  7. import com.j256.ormlite.dao.Dao;  
  8. import com.zhy.zhy_ormlite.bean.User;  
  9.   
  10. public class UserDao  
  11. {  
  12.     private Context context;  
  13.     private Dao<User, Integer> userDaoOpe;  
  14.     private DatabaseHelper helper;  
  15.   
  16.     public UserDao(Context context)  
  17.     {  
  18.         this.context = context;  
  19.         try  
  20.         {  
  21.             helper = DatabaseHelper.getHelper(context);  
  22.             userDaoOpe = helper.getDao(User.class);  
  23.         } catch (SQLException e)  
  24.         {  
  25.             e.printStackTrace();  
  26.         }  
  27.     }  
  28.   
  29.     /** 
  30.      * 增加一个用户 
  31.      * @param user 
  32.      */  
  33.     public void add(User user)  
  34.     {  
  35.         try  
  36.         {  
  37.             userDaoOpe.create(user);  
  38.         } catch (SQLException e)  
  39.         {  
  40.             e.printStackTrace();  
  41.         }  
  42.   
  43.     }//...other operations  
  44.   
  45.   
  46. }  

我们的所有的XXXDao遵循以上的风格~

好了,基本了解了我们的代码的结构~~ps:如果觉得不合理可以留言指出,如果觉得不能接收,直接忽略。。。


3、ORMLite外键引用

现在我们有两张表一张User,一张Article; 

Article中当然需要存储User的主键,作为关联~~那么在ORMLite中如何做到呢?

可能有人会直接在Article中声明一个int类型userId属性,当作普通属性处理搞定,这种做法并没有做,但是没有体现出面向对象的思想。

面向对象是这样的:Article属于某个User

类这么定义:

[java]  view plain copy
  1. package com.zhy.zhy_ormlite.bean;  
  2.   
  3. import com.j256.ormlite.field.DatabaseField;  
  4. import com.j256.ormlite.table.DatabaseTable;  
  5.   
  6. @DatabaseTable(tableName = "tb_article")  
  7. public class Article  
  8. {  
  9.     @DatabaseField(generatedId = true)  
  10.     private int id;  
  11.     @DatabaseField  
  12.     private String title;  
  13.     @DatabaseField(canBeNull = true, foreign = true, columnName = "user_id")  
  14.     private User user;  
  15.   
  16.     public int getId()  
  17.     {  
  18.         return id;  
  19.     }  
  20.   
  21.     public void setId(int id)  
  22.     {  
  23.         this.id = id;  
  24.     }  
  25.   
  26.     public String getTitle()  
  27.     {  
  28.         return title;  
  29.     }  
  30.   
  31.     public void setTitle(String title)  
  32.     {  
  33.         this.title = title;  
  34.     }  
  35.   
  36.     public User getUser()  
  37.     {  
  38.         return user;  
  39.     }  
  40.   
  41.     public void setUser(User user)  
  42.     {  
  43.         this.user = user;  
  44.     }  
  45.   
  46.     @Override  
  47.     public String toString()  
  48.     {  
  49.         return "Article [id=" + id + ", title=" + title + ", user=" + user  
  50.                 + "]";  
  51.     }  
  52.   
  53. }  

不会去定义一个int类型的userId,而是直接定义一个User成员变量,表示本Article属于该User;

然后在User user属性上添加: @DatabaseField(canBeNull = true, foreign = true, columnName = "user_id")

canBeNull -表示不能为null;foreign=true表示是一个外键;columnName 列名

User类暂且就两个属性:

[java]  view plain copy
  1. package com.zhy.zhy_ormlite.bean;  
  2.   
  3. import com.j256.ormlite.field.DatabaseField;  
  4. import com.j256.ormlite.table.DatabaseTable;  
  5.   
  6. @DatabaseTable(tableName = "tb_user")  
  7. public class User   
  8. {  
  9.     @DatabaseField(generatedId = true)  
  10.     private int id;  
  11.     @DatabaseField(columnName = "name")  
  12.     private String name;  
  13.   
  14.   
  15.     public User()  
  16.     {  
  17.     }  
  18.   
  19.     public int getId()  
  20.     {  
  21.         return id;  
  22.     }  
  23.   
  24.     public void setId(int id)  
  25.     {  
  26.         this.id = id;  
  27.     }  
  28.   
  29.     public String getName()  
  30.     {  
  31.         return name;  
  32.     }  
  33.   
  34.     public void setName(String name)  
  35.     {  
  36.         this.name = name;  
  37.     }  
  38.   
  39.     @Override  
  40.     public String toString()  
  41.     {  
  42.         return "User [id=" + id + ", name=" + name   
  43.                 + "]";  
  44.     }  
  45.   
  46.       
  47.   
  48.   
  49.       
  50. }  

现在看我们的ArticleDao

[java]  view plain copy
  1. package com.zhy.zhy_ormlite.db;  
  2.   
  3. import java.sql.SQLException;  
  4. import java.util.List;  
  5.   
  6. import android.content.Context;  
  7.   
  8. import com.j256.ormlite.dao.Dao;  
  9. import com.zhy.zhy_ormlite.bean.Article;  
  10. import com.zhy.zhy_ormlite.bean.User;  
  11.   
  12. public class ArticleDao  
  13. {  
  14.     private Dao<Article, Integer> articleDaoOpe;  
  15.     private DatabaseHelper helper;  
  16.   
  17.     @SuppressWarnings("unchecked")  
  18.     public ArticleDao(Context context)  
  19.     {  
  20.         try  
  21.         {  
  22.             helper = DatabaseHelper.getHelper(context);  
  23.             articleDaoOpe = helper.getDao(Article.class);  
  24.         } catch (SQLException e)  
  25.         {  
  26.             e.printStackTrace();  
  27.         }  
  28.     }  
  29.   
  30.     /** 
  31.      * 添加一个Article 
  32.      * @param article 
  33.      */  
  34.     public void add(Article article)  
  35.     {  
  36.         try  
  37.         {  
  38.             articleDaoOpe.create(article);  
  39.         } catch (SQLException e)  
  40.         {  
  41.             e.printStackTrace();  
  42.         }  
  43.     }  
  44.   
  45.     /** 
  46.      * 通过Id得到一个Article 
  47.      * @param id 
  48.      * @return 
  49.      */  
  50.     @SuppressWarnings("unchecked")  
  51.     public Article getArticleWithUser(int id)  
  52.     {  
  53.         Article article = null;  
  54.         try  
  55.         {  
  56.             article = articleDaoOpe.queryForId(id);  
  57.             helper.getDao(User.class).refresh(article.getUser());  
  58.   
  59.         } catch (SQLException e)  
  60.         {  
  61.             e.printStackTrace();  
  62.         }  
  63.         return article;  
  64.     }  
  65.       
  66.     /** 
  67.      * 通过Id得到一篇文章 
  68.      * @param id 
  69.      * @return 
  70.      */  
  71.     public Article get(int id)  
  72.     {  
  73.         Article article = null;  
  74.         try  
  75.         {  
  76.             article = articleDaoOpe.queryForId(id);  
  77.   
  78.         } catch (SQLException e)  
  79.         {  
  80.             e.printStackTrace();  
  81.         }  
  82.         return article;  
  83.     }  
  84.   
  85.     /** 
  86.      * 通过UserId获取所有的文章 
  87.      * @param userId 
  88.      * @return 
  89.      */  
  90.     public List<Article> listByUserId(int userId)  
  91.     {  
  92.         try  
  93.         {  
  94.             return articleDaoOpe.queryBuilder().where().eq("user_id", userId)  
  95.                     .query();  
  96.         } catch (SQLException e)  
  97.         {  
  98.             e.printStackTrace();  
  99.         }  
  100.         return null;  
  101.     }  
  102.   
  103. }  

接下来看我们的测试类:

[java]  view plain copy
  1. public class OrmLiteDbTest extends AndroidTestCase  
  2. {  
  3.     public void testAddArticle()  
  4.     {  
  5.         User u = new User();  
  6.         u.setName("张鸿洋");  
  7.         new UserDao(getContext()).add(u);  
  8.         Article article = new Article();  
  9.         article.setTitle("ORMLite的使用");  
  10.         article.setUser(u);  
  11.         new ArticleDao(getContext()).add(article);  
  12.   
  13.     }  
  14.   
  15.     public void testGetArticleById()  
  16.     {  
  17.         Article article = new ArticleDao(getContext()).get(1);  
  18.         L.e(article.getUser() + " , " + article.getTitle());  
  19.     }  
  20.   
  21.     public void testGetArticleWithUser()  
  22.     {  
  23.   
  24.         Article article = new ArticleDao(getContext()).getArticleWithUser(1);  
  25.         L.e(article.getUser() + " , " + article.getTitle());  
  26.     }  
  27.       
  28.     public void testListArticlesByUserId()  
  29.     {  
  30.   
  31.         List<Article> articles = new ArticleDao(getContext()).listByUserId(1);  
  32.         L.e(articles.toString());  
  33.     }  

分别测试,添加一个Article;通过Id获取一个Article;通过Id获取一个Article且携带User;通过userId获取所有的Article;

主要看第三个:通过Id获取一个Article且携带User,testGetArticleWithUser(id)

如何值传一个Article的Id,然后能够拿到Article对象,且内部的user属性直接赋值呢?

两种方式:

1、即上述写法

[java]  view plain copy
  1. article = articleDaoOpe.queryForId(id);  
  2.             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的代码:

[java]  view plain copy
  1. public User get(int id)  
  2.     {  
  3.         try  
  4.         {  
  5.             return userDaoOpe.queryForId(id);  
  6.         } catch (SQLException e)  
  7.         {  
  8.             e.printStackTrace();  
  9.         }  
  10.         return null ;  
  11.     }  

测试代码:

[java]  view plain copy
  1. public void testGetUserById()  
  2.     {  
  3.         User user = new UserDao(getContext()).get(1);  
  4.         L.e(user.getName());  
  5.         if (user.getArticles() != null)  
  6.             for (Article article : user.getArticles())  
  7.             {  
  8.                 L.e(article.toString());  
  9.             }  
  10.     }  
输出:

[java]  view plain copy
  1. 09-07 22:49:06.484: E/zhy(7293): 张鸿洋  
  2. 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 

[java]  view plain copy
  1. QueryBuilder<Article, Integer> queryBuilder = articleDaoOpe  
  2.                 .queryBuilder();  
  3.         Where<Article, Integer> where = queryBuilder.where();  
  4.         where.eq("user_id"1);  
  5.         where.and();  
  6.         where.eq("name""xxx");  
  7.   
  8.         //或者  
  9.         articleDaoOpe.queryBuilder().//  
  10.                 where().//  
  11.                 eq("user_id"1).and().//  
  12.                 eq("name""xxx");  

上述两种都相当与:select * from tb_article where user_id = 1 and name = 'xxx' ; 

3、更复杂的查询

[java]  view plain copy
  1. where.or(  
  2.                     //  
  3.                     where.and(//  
  4.                             where.eq("user_id"1), where.eq("name""xxx")),  
  5.                     where.and(//  
  6.                             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中直接写如下代码:

[java]  view plain copy
  1. //事务操作  
  2.         TransactionManager.callInTransaction(helper.getConnectionSource(),  
  3.                 new Callable<Void>()  
  4.                 {  
  5.   
  6.                     @Override  
  7.                     public Void call() throws Exception  
  8.                     {  
  9.                         return null;  
  10.                     }  
  11.                 });  


8、其他操作

1、当Bean继承BaseDaoEnabled时,可以使用bean.create(bean);bean.update(bean)一类操作

例如:

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

[java]  view plain copy
  1. QueryBuilder<Article, Integer> articleBuilder = articleDaoOpe  
  2.                     .queryBuilder();  
  3.             QueryBuilder userBuilder = helper.getDao(User.class).queryBuilder();  
  4.             articleBuilder.join(userBuilder);  

Article与User做Join操作;


本篇主要想介绍在项目中如何写DataBaseHelper已经如何写BeanDao,以及列出了在项目中可能会用到的ORMLite的功能,如果需要详细了解,还请看ORMLite官方文档,源码中也会提供~~


转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39122981,本文出自【张鸿洋的博客】

源码点击下载


你可能感兴趣的:(android,ormlite)