@flyouting
        
        2014-03-31T11:04:18.000000Z
        字数 8918
        阅读 11475
    ORMLite这个框架恐怕是在ORM中被采用的比较多的一个。文档,实例i,源码都比较多,维护也不错。
可以通过官方发布页面下载jar包,ORMLite release page,目前最新的是4.48。在android应用中使用,我们需要下载ormlite-android-4.48.jar和ormlite-core-4.48.jar两个文件
@DatabaseTable(tableName = "Category")public class Category {@DatabaseField(generatedId = true)public int id;@DatabaseFieldpublic String cateName;@ForeignCollectionField(eager = false)public ForeignCollection<Item> items;}
@DatabaseTable 注解中,tableName 参数是可选的,也就是这个类对应的表名。如果没有特别指出,那么这个类名将默认作为表名。对于类中的每个需要存储的成员变量,都需要添加@DatabaseField注解。
@ForeignCollectionField 表示这个表中的数据在其他表中是外键,这里标记了items成员变量是一个匹配Category 的items集合。成员变量items的类型必须要么是ForeignCollection<T>要么是Collection<T>,没有其他的集合被支持。当然,这里的Item类必须有一个Category类型的外部变量。
@DatabaseTable(tableName = "item")public class Item {@DatabaseField(generatedId = true)public int id;@DatabaseFieldpublic String name;@DatabaseField(foreign = true, foreignAutoRefresh = true)public Category category;}
@DatabaseField 常用注解:
columnName  指定字段名,不指定则变量名作为字段名canBeNull      字段是否能被分配null值。默认是true。如果你设置成false,那么你每次在数据库中插入数据是都必须为这个字段提供值。dataType 指定字段的类型defaultValue 当我们在表中创建新的记录时的一个字段的默认值。默认情况下是没有这个值的width 字段的宽度,主要用于字符串字段。默认是0id 这个字段是否是id,默认是false。在一个class中只有一个成变量可以有这个值。id字段是一条记录的唯一标识而且是必需的,只能在generatedId和 generatedIdSequence其中选一个。generatedId 字段是否自动增加。默认为false。类中的一个成员变量设置了这个值,它告诉数据库每添加一条新记录都自动增加id。当一个有generatedid的对象被创建时使用Dao.create()方法,数据库将为记录生成一个id,它会被返回并且被create方法设置进对象。generatedIdSequence 序列编号的名字,这个值在生成的时候会被使用。和generatedId相似,但是你能够指定使用的序列名称。默认是没有的。foreign 指定这个字段的对象是一个外键,外键值是这个对象的idpersisted 指定是否持久化此变量,默认trueforeignAutoCreate 外键不存在时是否自动添加到外间表中foreignColumnName 外键字段指定的外键表中的哪个字段@ForeignCollectionField常用注解
eager 表示该集合是在初始化这个对象的时候,是否讲对象取出还是在遍历的时候才取出,默认false遍历的时候才取出,size()方法也会引起遍历给class添加了注解字段后,你也需要添加一个无参的包内可见的构造器。当一个对象在查询中被返回时,ORMLite使用java反射机制构造一个对象并且构造器需要被调用。
创建一个自己的DBHelper类,继承自OrmLiteSqliteOpenHelper,这个类可以在程序被安装时创建或者升级数据库,同时也可以提供一个DAO给其他的类使用。这个helper类需要实现onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) 和onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion)方法。一个用于生成数据库,一个用于升级数据库。
/*** Database helper class used to manage the creation and upgrading of your* database. This class also usually provides the DAOs used by the other* classes.*/public class DatabaseHelper extends OrmLiteSqliteOpenHelper {// name of the database file for your application -- change to something// appropriate for your appprivate static final String DATABASE_NAME = "demo.db";// any time you make changes to your database objects, you may have to// increase the database versionprivate static final int DATABASE_VERSION = 1;// the DAO object we use to access the tablesprivate RuntimeExceptionDao<Category, Integer> cateRuntimeDao = null;private RuntimeExceptionDao<Item, Integer> itemRuntimeDao = null;// 添加事物public DatabaseConnection conn;public DatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}/*** This is called when the database is first created. Usually you should* call createTable statements here to create the tables that will store* your data.*/@Overridepublic void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {try {Log.d(DatabaseHelper.class.getName(), "onCreate");conn = connectionSource.getSpecialConnection();TableUtils.createTable(connectionSource, Item.class);TableUtils.createTable(connectionSource, Category.class);// TableUtils.createTable(connectionSource, ArticleResponse.class);} catch (SQLException e) {Log.e(DatabaseHelper.class.getName(), "Can't create database", e);throw new RuntimeException(e);}}/*** This is called when your application is upgraded and it has a higher* version number. This allows you to adjust the various data to match the* new version number.*/@Overridepublic void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion,int newVersion) {try {Log.d(DatabaseHelper.class.getName(), "onUpgrade");TableUtils.dropTable(connectionSource, Item.class, true);TableUtils.dropTable(connectionSource, Category.class, true);// after we drop the old databases, we create the new onesonCreate(db, connectionSource);} catch (SQLException e) {Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e);throw new RuntimeException(e);}}/*** Returns the RuntimeExceptionDao (Database Access Object) version of a Dao* for our classes. It will create it or just give the cached value.* RuntimeExceptionDao only through RuntimeExceptions.*/public RuntimeExceptionDao<Item, Integer> getItemDao() {if (itemRuntimeDao == null) {itemRuntimeDao = getRuntimeExceptionDao(Item.class);}return itemRuntimeDao;}public RuntimeExceptionDao<Category, Integer> getCateDao() {if (cateRuntimeDao == null) {cateRuntimeDao = getRuntimeExceptionDao(Category.class);}return cateRuntimeDao;}/*** Close the database connections and clear any cached DAOs.*/@Overridepublic void close() {super.close();itemRuntimeDao = null;cateRuntimeDao = null;}}
创建DBManager,管理DBHelper。
public class DatabaseManager {/*** 全局对象*/private static DatabaseHelper mDatabaseHelper;private static Context context;private DatabaseManager() {}/*** @param context application context*/public static void init(Context context) {DatabaseManager.context = context;mDatabaseHelper = new DatabaseHelper(context);}/*** @return instance of the object* @throws IllegalStatException if init has not yet been called*/public static DatabaseHelper getHelper() {if (mDatabaseHelper == null) {mDatabaseHelper = new DatabaseHelper(context);}return mDatabaseHelper;}}
当然如果不喜欢用全局的,可以在Activity层面去使用。
private DatabaseHelper databaseHelper = null;@Overrideprotected void onDestroy() {super.onDestroy();/** You'll need this in your class to release the helper when done.*/if (databaseHelper != null) {OpenHelperManager.releaseHelper();databaseHelper = null;}}/*** You'll need this in your class to get the helper from the manager once per class.*/private DatabaseHelper getHelper() {if (databaseHelper == null) {databaseHelper = OpenHelperManager.getHelper(this, DatabaseHelper.class);}return databaseHelper;}
在DBHelper里其实已经添加了获取DAO的接口,Dao<T,V>,包含两个泛型,第一个泛型表DAO操作的类,第二个表示操作类的主键类型。 
DAO里的主要方法:
create 插入一条数据createIfNotExists 如果不存在则插入createOrUpdate 如果指定id则更新queryForId 更具id查找update 查找出数据delete 删除数据queryBuilder() 创建一个查询生成器:进行复杂查询deleteBuilder() 创建一个删除生成器,进程复杂条件删除updateBuilder() 创建修条件生成器,进行复杂条件修改首先模拟一下数据:
private List<Category> cateList = new ArrayList<Category>();private List<Item> itemList = new ArrayList<Item>();for (int i = 0; i < 100; i++) {Category cate = new Category();cate.cateName = "Category " + i;cateList.add(cate);for (int j = 0; j < 3; j++) {Item item = new Item();item.name = "item " + j + " from Category " + i;item.category = cate;itemList.add(item);}}
然后是插入数据的异步:
class InstertAsyncTask extends AsyncTask<List<Category>, Object, Object> {private List<Category> cateList;private List<Item> itemList;public InstertAsyncTask(List<Category> cateList, List<Item> items) {this.cateList = cateList;this.itemList = items;}@Overrideprotected Object doInBackground(final List<Category>... params) {try {connection = new AndroidDatabaseConnection(DatabaseManager.getHelper().getWritableDatabase(), true);final RuntimeExceptionDao<Category, Integer> cateRuntimeDao = DatabaseManager.getHelper().getCateDao();final RuntimeExceptionDao<Item, Integer> itemRuntimeDao = DatabaseManager.getHelper().getItemDao();TransactionManager.callInTransaction(DatabaseManager.getHelper().getConnectionSource(), new Callable<Void>() {@Overridepublic Void call() throws Exception {// TODO Auto-generated method stubfor (Category cate : cateList) {cateRuntimeDao.create(cate);}for (Item item : itemList) {itemRuntimeDao.create(item);}return null;}});} catch (SQLException e) {}return null;}}
class DeleteAsyncTask extends AsyncTask<String, Object, Object> {private List<Category> cateList;public DeleteAsyncTask(List<Category> cateList) {this.cateList = cateList;}@Overrideprotected Object doInBackground(String... params) {final RuntimeExceptionDao<Category, Integer> cateRuntimeDao = DatabaseManager.getHelper().getCateDao();cateRuntimeDao.delete(cateList);return null;}}
同样是通过DAO操作的,可以传入一个List对象,可以传入一个model对象,也可以传入ID。
class UpdateCardReadStatusAsyncTask extends AsyncTask<Object, Object, Object> {Category category = null;UpdateCardReadStatusAsyncTask(Category category) {this.category = category;}@Overrideprotected Object doInBackground(Object... params) {DatabaseManager.getHelper().getCateDao().update(category);return null;}}
把修改过后的对象传入,通过DAO执行update方法即可更新。
这里只是举个例子:
List<Category> categorys = DatabaseManager.getHelper().getCateDao().queryBuilder().orderBy("publish_date", false).limit(20l).where().lt("publish_date", publish_time).and().eq("kind", kind).query();
这次查询是返回一个按照publish_date时间降序,个数为20个,publish_date时间小于指定时间,kind类型等于指定类型的一个List表。 
查询可以用原始查询语句,这适合比较复杂的查询条件。 
queryBuilder()里有常见的查询条件,可以查询API。 
需要注意的是,这次查询完毕后,对象包含的List对象其实是ForeignCollection<Item>类型的,跟我们平时用的ArrayList是不一样的,我们需要些个get方法,返回一个 new ArrayList<Item>().addAll(items);
批量操作肯定是要添加事务的,这里有两种添加事务的方法。 
一种是
TransactionManager.callInTransaction(DatabaseManager.getHelper().getConnectionSource(), new Callable<Void>() {@Overridepublic Void call() throws Exception {// TODO Auto-generated method stub数据操作return null;}});
另一种是:
savepoint = connection.setSavePoint(POINTNAME);time = System.currentTimeMillis();for (Category cate : cateList) {cateRuntimeDao.create(cate);}for (Item item : itemList) {itemRuntimeDao.create(item);}connection.commit(savepoint);
如果不执行commit操作,就会回滚数据库。当然第二种方法的处理需要加try-catch块。
作者:@flyouting 
时间:2014/03/31