@flyouting
2014-03-31T19:04:18.000000Z
字数 8918
阅读 10881
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;
@DatabaseField
public 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;
@DatabaseField
public 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 app
private static final String DATABASE_NAME = "demo.db";
// any time you make changes to your database objects, you may have to
// increase the database version
private static final int DATABASE_VERSION = 1;
// the DAO object we use to access the tables
private 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.
*/
@Override
public 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.
*/
@Override
public 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 ones
onCreate(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.
*/
@Override
public 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;
@Override
protected 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;
}
@Override
protected 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>() {
@Override
public Void call() throws Exception {
// TODO Auto-generated method stub
for (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;
}
@Override
protected 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;
}
@Override
protected 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>() {
@Override
public 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