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());
}
这本是一个简单的查询,但为什么我们还需要写这么多无用的代码?
想想在这些情况:
- 添加或删除列
- 为了在操作其他表、进行其他的查询或者支持其他的数据类型,我们还不得不写下更多的废代码。
我们希望这些操作的代码能变得短小,但同时又能方便维护和富于表现力(一下就能看懂做了哪些操作)。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支持许多的查询操作:
- SELECT
- UPDATE
- INSERT
- DETELE
- 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语句
有两种方式更新数据:
- 使用
SQLite.update()
方法或者Update
类 - 使用
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
语句对于多对多关系是一个很好的操作符。
比如我们有一个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();