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类

@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成员变量是一个匹配Categoryitems集合。成员变量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 字段的宽度,主要用于字符串字段。默认是0
  • id 这个字段是否是id,默认是false。在一个class中只有一个成变量可以有这个值。id字段是一条记录的唯一标识而且是必需的,只能在generatedId和 generatedIdSequence其中选一个。
  • generatedId 字段是否自动增加。默认为false。类中的一个成员变量设置了这个值,它告诉数据库每添加一条新记录都自动增加id。当一个有generatedid的对象被创建时使用Dao.create()方法,数据库将为记录生成一个id,它会被返回并且被create方法设置进对象。
  • generatedIdSequence 序列编号的名字,这个值在生成的时候会被使用。和generatedId相似,但是你能够指定使用的序列名称。默认是没有的。
  • foreign 指定这个字段的对象是一个外键,外键值是这个对象的id
  • persisted 指定是否持久化此变量,默认true
  • foreignAutoCreate 外键不存在时是否自动添加到外间表中
  • foreignColumnName 外键字段指定的外键表中的哪个字段

@ForeignCollectionField常用注解

  • eager 表示该集合是在初始化这个对象的时候,是否讲对象取出还是在遍历的时候才取出,默认false遍历的时候才取出,size()方法也会引起遍历
  • columnName
  • orderColumnName
  • foreignFieldName

添加无参构造方法

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

创建DB Helper

创建一个自己的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

创建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;
    }


创建DAO

在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块。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值