SQL操作的封装类

在Android中对数据库的操作很多时候还是得用SQL语句,手写SQL语句的操作是繁琐、难看而又容易出错的。为了使对数据库的操作更加简单好用,我们对数据库操作进行了封装,同时尽量保证了与原生SQL语法的相似,使得更容易上手。

在第一节中,我们将演示封装类是如何大大简化你的代码的。

一个例子

比如我们想要从Ant中选出所有为“worker”的雌蚂蚁。这个操作的SQL语句很简单:

SELECT * FROM Ant where type = 'worker' AND isMale = 0;

而如果要将数据库里面的数据转为我们可用的数据,在Android中我们需要写这些代码:

String[] args = new String[2];
args[0] = "worker";
args[1] = "0";
Cursor cursor = db.rawQuery("SELECT * FROM Ant where type = ? AND isMale = ?", args);
final List<Ant> ants = new ArrayList<Ant>();
Ant ant;

if (cursor.moveToFirst()) {
  do {
    // get each column and then set it on each
    ant = new Ant();
    ant.setId(cursor.getLong(cursor.getColumnIndex("id")));
    ant.setType(cursor.getString(cursor.getColumnIndex("type")));
    ant.setIsMale(cursor.getInt(cursor.getColumnIndex("isMale") == 1);
    ant.setQueenId(cursor.getLong(cursor.getColumnIndex("queen_id")));
    ants.add(ant);
  }
  while (cursor.moveToNext());
}

这本是一个简单的查询,但为什么我们还需要写这么多无用的代码?

想想在这些情况:

  1. 添加或删除列
  2. 为了在操作其他表、进行其他的查询或者支持其他的数据类型,我们还不得不写下更多的废代码。

我们希望这些操作的代码能变得短小,但同时又能方便维护和富于表现力(一下就能看懂做了哪些操作)。DBFlow正是为你提供了这些:

// 同步执行操作
List<Ant> devices = SQLite.select().from(Ant.class)
  .where(Ant_Table.type.eq("worker"))
  .and(Ant_Table.isMale.eq(false)).queryList();

// 异步执行操作
  SQLite.select()
  .from(DeviceObject.class)
  .where(Ant_Table.type.eq("worker"))
  .and(Ant_Table.isMale.eq(false))
  .async().queryList(transactionListener);

DBFlow支持许多的查询操作:

  1. SELECT
  2. UPDATE
  3. INSERT
  4. DETELE
  5. JOIN

SELECT操作和事务

Select用于从数据库中查找数据。我们还可以使用TransactionManager来进行事务(对于大量操作更推荐使用事务)

// Query a List
SQLite.select().from(SomeTable.class).queryList();
SQLite.select().from(SomeTable.class).where(conditions).queryList();

// Query Single Model
SQLite.select().from(SomeTable.class).querySingle();
SQLite.select().from(SomeTable.class).where(conditions).querySingle();

// Query a Table List and Cursor List
SQLite.select().from(SomeTable.class).where(conditions).queryTableList();
SQLite.select().from(SomeTable.class).where(conditions).queryCursorList();

// Query into a ModelContainer!
SQLite.select().from(SomeTable.class).where(conditions).queryModelContainer(new MapModelContainer<>(SomeTable.class));

// SELECT methods
SQLite.select().distinct().from(table).queryList();
SQLite.select().from(table).queryList();
SQLite.select(Method.avg(SomeTable_Table.salary))
  .from(SomeTable.class).queryList();
SQLite.select(Method.max(SomeTable_Table.salary))
  .from(SomeTable.class).queryList();

// Transact a query on the DBTransactionQueue
TransactionManager.getInstance().addTransaction(
  new SelectListTransaction<>(new Select().from(SomeTable.class).where(conditions),
  new TransactionListenerAdapter<List<SomeTable>>() {
    @Override
    public void onResultReceived(List<SomeTable> someObjectList) {
      // retrieved here
});

// Selects Count of Rows for the SELECT statment
long count = SQLite.selectCountOf()
  .where(conditions).count();

Oeder By

// true为'ASC'正序, false为'DESC'反序
SQLite.select()
  .from(table)
  .where()
  .orderBy(Customer_Table.customer_id, true)
  .queryList();

Group By

SQLite.select()
  .from(table)
  .groupBy(Customer_Table.customer_id, Customer_Table.customer_name)
  .queryList();

Having

SQLite.select()
  .from(table)
  .groupBy(Customer_Table.customer_id, Customer_Table.customer_name))
  .having(Customer_Table.customer_id.greaterThan(2))
  .queryList();

LIMIT + OFFSET (分页)

SQLite.select()
  .from(table)
  .limit(3)
  .offset(2)
  .queryList();

UPDATE语句

有两种方式更新数据:

  1. 使用SQLite.update()方法或者Update
  2. 使用TransactionManager运行事务(尽管是异步的,但是线程安全的)

在这一节,我们将展示批量更新数据。

在之前的例子中,我们想要将所有的“worker”雄蚂蚁变为“other”,因为这些蚂蚁们变懒了都不想工作了(笑)。

SQL语句描述为:

UPDATE Ant SET type = 'other' WHERE male = 1 AND type = 'worker';

DBFlow中这样进行这个操作:

// Native SQL wrapper
Where<Ant> update = SQLite.update(Ant.class)
  .set(Ant_Table.type.eq("other"))
  .where(Ant_Table.type.is("worker"))
    .and(Ant_Table.isMale.is(true));

//译者注:queryClose()方法在3.0.0beta2中并没有找到,可能是一个过时的方法。
update.queryClose();

// TransactionManager (more methods similar to this one)
TransactionManager
        .getInstance()
        .addTransaction(
                new QueryTransaction(
                        DBTransactionInfo.create(BaseTransaction.PRIORITY_UI),
                update);

DELETE语句

// Delete a whole table
Delete.table(MyTable.class, conditions);

// Delete multiple instantly
Delete.tables(MyTable1.class, MyTable2.class);

// Delete using query
SQLite.delete(MyTable.class)
  .where(DeviceObject_Table.carrier.is("T-MOBILE"))
    .and(DeviceObject_Table.device.is("Samsung-Galaxy-S5"))
  .query();

JOIN语句

JOIN example

JOIN语句对于多对多关系是一个很好的操作符。

比如我们有一个Customer表和一个Reservations表:

SELECT FROM `Customer` AS `C` INNER JOIN `Reservations` AS `R` ON `C`.`customerId`=`R`.`customerId`
// 由于查询结果可能没有合适的Table类可以容纳,所以可以通过`@QueryModel`注解的Model以及`queryCustomList()`方法来容纳结果。
List<CustomTable> customers = new Select()   
  .from(Customer.class).as("C")   
  .join(Reservations.class, JoinType.INNER).as("R")    
  .on(Customer_Table.customerId
      .withTable(new NameAlias("C"))
    .eq(Reservations_Table.customerId.withTable("R"))
    .queryCustomList(CustomTable.class);

对于IProperty.withTable()方法,我们既可以像上面那样使用NameAlias别名,也可以直接使用表示关系,例如上面的例子可简化为:

SELECT EMP_ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT
      ON COMPANY.ID = DEPARTMENT.EMP_ID

DBFlow:

SQLite.select(Company_Table.EMP_ID, Company_Table.DEPT)
  .from(Company.class)
  .leftOuterJoin(Department.class)
  .on(Company_Table.ID.withTable().eq(Department_Table.EMP_ID.withTable()))
  .queryList();