[关闭]
@flyouting 2014-03-31T11:04:18.000000Z 字数 8918 阅读 10501

Android ORM框架之 ORMLite

ORMLite这个框架恐怕是在ORM中被采用的比较多的一个。文档,实例i,源码都比较多,维护也不错。

下载ORMLite Jar包

可以通过官方发布页面下载jar包,ORMLite release page,目前最新的是4.48。在android应用中使用,我们需要下载ormlite-android-4.48.jar和ormlite-core-4.48.jar两个文件

工程使用

配置model类

  1. @DatabaseTable(tableName = "Category")
  2. public class Category {
  3. @DatabaseField(generatedId = true)
  4. public int id;
  5. @DatabaseField
  6. public String cateName;
  7. @ForeignCollectionField(eager = false)
  8. public ForeignCollection<Item> items;
  9. }

@DatabaseTable 注解中,tableName 参数是可选的,也就是这个类对应的表名。如果没有特别指出,那么这个类名将默认作为表名。对于类中的每个需要存储的成员变量,都需要添加@DatabaseField注解。

@ForeignCollectionField 表示这个表中的数据在其他表中是外键,这里标记了items成员变量是一个匹配Categoryitems集合。成员变量items的类型必须要么是ForeignCollection<T>要么是Collection<T>,没有其他的集合被支持。当然,这里的Item类必须有一个Category类型的外部变量。

  1. @DatabaseTable(tableName = "item")
  2. public class Item {
  3. @DatabaseField(generatedId = true)
  4. public int id;
  5. @DatabaseField
  6. public String name;
  7. @DatabaseField(foreign = true, foreignAutoRefresh = true)
  8. public Category category;
  9. }

@DatabaseField 常用注解:

@ForeignCollectionField常用注解

添加无参构造方法

给class添加了注解字段后,你也需要添加一个无参的包内可见的构造器。当一个对象在查询中被返回时,ORMLite使用java反射机制构造一个对象并且构造器需要被调用。

创建DB Helper

创建一个自己的DBHelper类,继承自OrmLiteSqliteOpenHelper,这个类可以在程序被安装时创建或者升级数据库,同时也可以提供一个DAO给其他的类使用。这个helper类需要实现onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource)onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion)方法。一个用于生成数据库,一个用于升级数据库。

  1. /**
  2. * Database helper class used to manage the creation and upgrading of your
  3. * database. This class also usually provides the DAOs used by the other
  4. * classes.
  5. */
  6. public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
  7. // name of the database file for your application -- change to something
  8. // appropriate for your app
  9. private static final String DATABASE_NAME = "demo.db";
  10. // any time you make changes to your database objects, you may have to
  11. // increase the database version
  12. private static final int DATABASE_VERSION = 1;
  13. // the DAO object we use to access the tables
  14. private RuntimeExceptionDao<Category, Integer> cateRuntimeDao = null;
  15. private RuntimeExceptionDao<Item, Integer> itemRuntimeDao = null;
  16. // 添加事物
  17. public DatabaseConnection conn;
  18. public DatabaseHelper(Context context) {
  19. super(context, DATABASE_NAME, null, DATABASE_VERSION);
  20. }
  21. /**
  22. * This is called when the database is first created. Usually you should
  23. * call createTable statements here to create the tables that will store
  24. * your data.
  25. */
  26. @Override
  27. public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
  28. try {
  29. Log.d(DatabaseHelper.class.getName(), "onCreate");
  30. conn = connectionSource.getSpecialConnection();
  31. TableUtils.createTable(connectionSource, Item.class);
  32. TableUtils.createTable(connectionSource, Category.class);
  33. // TableUtils.createTable(connectionSource, ArticleResponse.class);
  34. } catch (SQLException e) {
  35. Log.e(DatabaseHelper.class.getName(), "Can't create database", e);
  36. throw new RuntimeException(e);
  37. }
  38. }
  39. /**
  40. * This is called when your application is upgraded and it has a higher
  41. * version number. This allows you to adjust the various data to match the
  42. * new version number.
  43. */
  44. @Override
  45. public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion,
  46. int newVersion) {
  47. try {
  48. Log.d(DatabaseHelper.class.getName(), "onUpgrade");
  49. TableUtils.dropTable(connectionSource, Item.class, true);
  50. TableUtils.dropTable(connectionSource, Category.class, true);
  51. // after we drop the old databases, we create the new ones
  52. onCreate(db, connectionSource);
  53. } catch (SQLException e) {
  54. Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e);
  55. throw new RuntimeException(e);
  56. }
  57. }
  58. /**
  59. * Returns the RuntimeExceptionDao (Database Access Object) version of a Dao
  60. * for our classes. It will create it or just give the cached value.
  61. * RuntimeExceptionDao only through RuntimeExceptions.
  62. */
  63. public RuntimeExceptionDao<Item, Integer> getItemDao() {
  64. if (itemRuntimeDao == null) {
  65. itemRuntimeDao = getRuntimeExceptionDao(Item.class);
  66. }
  67. return itemRuntimeDao;
  68. }
  69. public RuntimeExceptionDao<Category, Integer> getCateDao() {
  70. if (cateRuntimeDao == null) {
  71. cateRuntimeDao = getRuntimeExceptionDao(Category.class);
  72. }
  73. return cateRuntimeDao;
  74. }
  75. /**
  76. * Close the database connections and clear any cached DAOs.
  77. */
  78. @Override
  79. public void close() {
  80. super.close();
  81. itemRuntimeDao = null;
  82. cateRuntimeDao = null;
  83. }
  84. }

创建DBManager

创建DBManager,管理DBHelper。

  1. public class DatabaseManager {
  2. /**
  3. * 全局对象
  4. */
  5. private static DatabaseHelper mDatabaseHelper;
  6. private static Context context;
  7. private DatabaseManager() {
  8. }
  9. /**
  10. * @param context application context
  11. */
  12. public static void init(Context context) {
  13. DatabaseManager.context = context;
  14. mDatabaseHelper = new DatabaseHelper(context);
  15. }
  16. /**
  17. * @return instance of the object
  18. * @throws IllegalStatException if init has not yet been called
  19. */
  20. public static DatabaseHelper getHelper() {
  21. if (mDatabaseHelper == null) {
  22. mDatabaseHelper = new DatabaseHelper(context);
  23. }
  24. return mDatabaseHelper;
  25. }
  26. }

当然如果不喜欢用全局的,可以在Activity层面去使用。

  1. private DatabaseHelper databaseHelper = null;
  2. @Override
  3. protected void onDestroy() {
  4. super.onDestroy();
  5. /*
  6. * You'll need this in your class to release the helper when done.
  7. */
  8. if (databaseHelper != null) {
  9. OpenHelperManager.releaseHelper();
  10. databaseHelper = null;
  11. }
  12. }
  13. /**
  14. * You'll need this in your class to get the helper from the manager once per class.
  15. */
  16. private DatabaseHelper getHelper() {
  17. if (databaseHelper == null) {
  18. databaseHelper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
  19. }
  20. return databaseHelper;
  21. }

创建DAO

在DBHelper里其实已经添加了获取DAO的接口,Dao<T,V>,包含两个泛型,第一个泛型表DAO操作的类,第二个表示操作类的主键类型。
DAO里的主要方法:

数据增删改查

首先模拟一下数据:

  1. private List<Category> cateList = new ArrayList<Category>();
  2. private List<Item> itemList = new ArrayList<Item>();
  3. for (int i = 0; i < 100; i++) {
  4. Category cate = new Category();
  5. cate.cateName = "Category " + i;
  6. cateList.add(cate);
  7. for (int j = 0; j < 3; j++) {
  8. Item item = new Item();
  9. item.name = "item " + j + " from Category " + i;
  10. item.category = cate;
  11. itemList.add(item);
  12. }
  13. }

然后是插入数据的异步:

  1. class InstertAsyncTask extends AsyncTask<List<Category>, Object, Object> {
  2. private List<Category> cateList;
  3. private List<Item> itemList;
  4. public InstertAsyncTask(List<Category> cateList, List<Item> items) {
  5. this.cateList = cateList;
  6. this.itemList = items;
  7. }
  8. @Override
  9. protected Object doInBackground(final List<Category>... params) {
  10. try {
  11. connection = new AndroidDatabaseConnection(DatabaseManager.getHelper()
  12. .getWritableDatabase(), true);
  13. final RuntimeExceptionDao<Category, Integer> cateRuntimeDao = DatabaseManager
  14. .getHelper()
  15. .getCateDao();
  16. final RuntimeExceptionDao<Item, Integer> itemRuntimeDao = DatabaseManager
  17. .getHelper()
  18. .getItemDao();
  19. TransactionManager.callInTransaction(DatabaseManager.getHelper()
  20. .getConnectionSource(), new Callable<Void>() {
  21. @Override
  22. public Void call() throws Exception {
  23. // TODO Auto-generated method stub
  24. for (Category cate : cateList) {
  25. cateRuntimeDao.create(cate);
  26. }
  27. for (Item item : itemList) {
  28. itemRuntimeDao.create(item);
  29. }
  30. return null;
  31. }
  32. });
  33. } catch (SQLException e) {
  34. }
  35. return null;
  36. }
  37. }

  1. class DeleteAsyncTask extends AsyncTask<String, Object, Object> {
  2. private List<Category> cateList;
  3. public DeleteAsyncTask(List<Category> cateList) {
  4. this.cateList = cateList;
  5. }
  6. @Override
  7. protected Object doInBackground(String... params) {
  8. final RuntimeExceptionDao<Category, Integer> cateRuntimeDao = DatabaseManager
  9. .getHelper()
  10. .getCateDao();
  11. cateRuntimeDao.delete(cateList);
  12. return null;
  13. }
  14. }

同样是通过DAO操作的,可以传入一个List对象,可以传入一个model对象,也可以传入ID。

  1. class UpdateCardReadStatusAsyncTask extends AsyncTask<Object, Object, Object> {
  2. Category category = null;
  3. UpdateCardReadStatusAsyncTask(Category category) {
  4. this.category = category;
  5. }
  6. @Override
  7. protected Object doInBackground(Object... params) {
  8. DatabaseManager
  9. .getHelper()
  10. .getCateDao().update(category);
  11. return null;
  12. }
  13. }

把修改过后的对象传入,通过DAO执行update方法即可更新。

这里只是举个例子:

  1. List<Category> categorys = DatabaseManager
  2. .getHelper()
  3. .getCateDao().queryBuilder()
  4. .orderBy("publish_date", false).limit(20l)
  5. .where().lt("publish_date", publish_time).and().eq("kind", kind)
  6. .query();

这次查询是返回一个按照publish_date时间降序,个数为20个,publish_date时间小于指定时间,kind类型等于指定类型的一个List表。
查询可以用原始查询语句,这适合比较复杂的查询条件。
queryBuilder()里有常见的查询条件,可以查询API。
需要注意的是,这次查询完毕后,对象包含的List对象其实是ForeignCollection<Item>类型的,跟我们平时用的ArrayList是不一样的,我们需要些个get方法,返回一个 new ArrayList<Item>().addAll(items);

添加事务

批量操作肯定是要添加事务的,这里有两种添加事务的方法。
一种是

  1. TransactionManager.callInTransaction(DatabaseManager.getHelper()
  2. .getConnectionSource(), new Callable<Void>() {
  3. @Override
  4. public Void call() throws Exception {
  5. // TODO Auto-generated method stub
  6. 数据操作
  7. return null;
  8. }
  9. });

另一种是:

  1. savepoint = connection.setSavePoint(POINTNAME);
  2. time = System.currentTimeMillis();
  3. for (Category cate : cateList) {
  4. cateRuntimeDao.create(cate);
  5. }
  6. for (Item item : itemList) {
  7. itemRuntimeDao.create(item);
  8. }
  9. connection.commit(savepoint);

如果不执行commit操作,就会回滚数据库。当然第二种方法的处理需要加try-catch块。

作者:@flyouting
时间:2014/03/31

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注