安卓GreenDao框架⼀些进阶⽤法整理
⼤致分为以下⼏个⽅⾯:
1. ⼀些查询指令整理
2. 使⽤SQL语句进⾏特殊查询
3. 检测表字段是否存在
4. 数据库升级
5. 数据库表字段赋初始值
⼀、查询指令整理
1.链式执⾏的指令
UserDao().queryBuilder().
XXX.
XXX.
XXX.
list();
⼀般的查询语句会在中间xxx的位置加上各种判断和过滤的⽅法指令,除了最后的终结指令list()或unique()返回的是集合或业务对象,其他的都是返回QueryBuilder对象,⼤多数情况下XXX的位置都是填上where语句,还有⼀些其他和sql关联的语句便于使⽤。
“whereOr” where语句⾥⾯写的条件都是⽤“且”连接,whereOr⾥的语句使⽤“或”连接
“distinct” 直接过滤掉重负字段
“limit” 分页n个⼀页,⼀般和offset结合使⽤
“offset” 忽略查询出的前n条结果
“orderAsc” 以字段升序排序
“orderDesc”以字段降序
“preferLocalizedStringOrder” 本地化字符串排序
“orderCustom” ⾃定义排序⾥⾯需要传两个参数:⼀个属性和对应的排序⽅案 ASC 或是 DESC
“orderRaw” 也是⾃定义排序,把字段和排序⽅案写在⼀个字符串传⼊
“stringOrderCollation” 也是⾃定义排序可以合并多个升降排序⽅案以⽇期升序且价格降序
2.条件⾥的指令
UserDao().queryBuilder().
where(UserDao.Properties.UserId.in(userIdList), UserDao.Properties.UserAge.eq(19)).
list();
⼀个简单的where语句⼤概是这样,在where的括号⾥⾯可以并列的写很多条件,其中全部以“且” 来连接。除了上⾯
的“in”和“eq”还有很多其他判断条件
“notEq” 和eq相反,别傻傻在再去外⾯敲“!”取反
“notIn” 同上
“or” 或者
“like” 就是sql语句的LIKE "%"+string+"%"
“between” 也就是BETWEEN ? AND ? 可以取两个值的区间 (但是这条语句要慎⽤,不同的数据库不⼀样,有的是A<;条件
<B,有的是A<=条件<=B)
“gt” 相当于 >
“ge”相当于 >=
“lt” 相当于 <
“le”相当于 <=
“isNull” 为空
“notIsNull” 不为空
⼆、使⽤SQL语句进⾏特殊查询
⼀般遇到普通的增删改查操作⽆法轻易实现的功能,会使⽤这种rawQuery的⽅式。我经常遇到的也就是两种场景:
1.使⽤SELECT DISTINCT
常⽤与⼀对多关系,假设图书馆现在有个“⽤户存书表” 有的⽤户有20本书,表⾥就会有20条他的数据,每条对应⼀本不同的书。
这时假设有个需求,查出这个表中,所有的⽤户名字,不许重复。这时候⽤普通的查询指令就会⾮常⿇烦了,需要使⽤SELECT DISTINCT指令查出某列名所有不重复的条⽬。
String queryString =
"SELECT DISTINCT " + UserBookDao.lumnName + " FROM " + UserBookDao.TABLENAME
+ " ORDER BY "
+ UserBookDao.Properties.CreatedTime
+ " DESC "
+ " LIMIT "
+ page * LIMIT_NUM
+ " , "
+ LIMIT_NUM;
ArrayList<String> result = new ArrayList<>();
Cursor c = Database().rawQuery(queryString,new String[]{});
try {
if (c != null) {
if (c.moveToFirst()) {
do {
result.String(0));
} while (c.moveToNext());
}
}
} finally {
if (c != null) {
c.close();
}
}
⼤概代码的画风就是这个样⼦,先拼接出⼀个符合sql语法的字符串,上⾯也随机加了⼀写其他的操作指令字段排序和分页,使得查询指令看上去更加完整,然后使⽤游标来接收上⾯的查询结果。
可能⼤多数查询的时候会带上⼀些参数,⽐如where XX = XX 的过滤条件,假设有个需求需要在之前的查询⽤户需求上加上对出版社和图书价格的限制,则查询⽅式如下
String queryString =
"SELECT DISTINCT " + UserBookDao.lumnName + " FROM " + UserBookDao.TABLENAME // 董铂然博客园
+ " WHERE "
+ UserBookDao.lumnName + " = ?"
+ " AND "
+ UserBookDao.lumnName + " > ?"
+ " ORDER BY "
+ UserBookDao.Properties.CreatedTime
+ " DESC ";
ArrayList<String> result = new ArrayList<>();
Cursor c = Database().rawQuery(queryString, new String[]{"某出版社"),
String.valueOf(100.00)});
try {
if (c != null) {
if (c.moveToFirst()) {
do {
result.String(0));
} while (c.moveToNext());
}
}
isnull的用法} finally {
if (c != null) {
c.close();
}
}
带上参数的查询字符串需要在上⾯使⽤问号占位,然后在下⾯⽤rawQuery带参数的api⾥填上相关的⼊参。
2. SELECT同时查询多个字段
还是⽤这个查书的例⼦,假设⼀下要查“书名”、“出版社”、“价格” 三个字段
String queryString = "SELECT "
+ UserBookDao.TABLENAME + "." + UserBookDao.lumnName + ","
+ UserBookDao.TABLENAME + "." + UserBookDao.lumnName + ","
+ UserBookDao.TABLENAME + "." + UserBookDao.lumnName + " "
+ "FROM "
+ UserBookDao.TABLENAME + " "
+ "WHERE"
+ UserBookDao.Properties.Price + " > 100.00 ";
Cursor cursor = null;
try {
cursor = Database().rawQuery(queryString,new String[]{});
if (cursor == null) {
return payMap;
}
/
/ 取出三个字段分别对应的索引,下⾯再对着索引去取值
int nameIndex = ColumnIndex(UserBookDao.lumnName);
int publisherIndex = ColumnIndex(UserBookDao.lumnName);
int priceIndex = ColumnIndex(UserBookDao.lumnName);
if (nameIndex != -1 && publisherIndex != -1 && priceIndex != -1) {
while (veToNext()) {
String name = String(nameIndex);
String publisher = String(publisherIndex);
Double price = Double(priceIndex);
// 这⾥取到三个字段⾃⼰是存模型还是字典⾃⼰处理。
}
}
} finally {
if (null != cursor) {
cursor.close();
}
}
下⾯可以⼀次性的取出三个所需字段进⾏使⽤,需要先得到字段对应索引,然后再对着索引取值。
三、检测表字段是否存在
private boolean hasColumn(SQLiteDatabase db, String tableName, String column) {
if (TextUtils.isEmpty(tableName) || TextUtils.isEmpty(column)) {
return false;
}
Cursor cursor = null;
try {
cursor = db.query(tableName, null, null, null, null, null, null);
if (null != cursor && ColumnIndex(column) != -1) {
return true;
}
} finally {
if (null != cursor) {
cursor.close();
}
}
return false;
}
和上⾯取游标的⽅式类似,取出的列索引值如果不是-1,则代表能够取到这个字段返回true,否则和⼊参⾮法⼀起返回fasle。
四、数据库升级
这边会调⽤上⾯判断列名是否已经存在的⽅法。
然后重写⽗类的这个onUpgrade⽅法
private static class DemoOpenHelper extends DaoMaster.OpenHelper {
public DemoOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 数据库的版本控制可以随着版本叠加不断增加差值
if (oldVersion < 2) {
if (!hasColumn(db, UserBookDao.TABLENAME, UserBookDao.lumnName)) {
String sql = "alter table " + UserBookDao.TABLENAME +
" add COLUMN " + UserBookDao.lumnName + " TEXT";
}
if (!hasColumn(db, UserBookDao.TABLENAME, UserBookDao.lumnName)) {
String sql = "alter table " + UserBookDao.TABLENAME +
" add COLUMN " + UserBookDao.lumnName + " INTEGER";
}
}
}
}
除了上⾯的修改表,如果改动太多或是换了表明,还可以直接删了重建(这么做的话之前的数据也就删了)
if (oldVersion < 3) {
UserDao.dropTable(new StandardDatabase(db),true);
}
五、数据库表字段赋初始值
有些字段的初始值如果你不希望是0,或是空字符串,可以赋初始值。现在的赋值初始值就分为两种情况了
1.建表时附初始值
在3.0以前的版本还是要写⼀个module,⾥⾯写类似代码来建表的
private static void addUser(Schema schema) {
Entity user = schema.addEntity("User");
user.addIdProperty();
user.addStringProperty("name").notNull().defValue("\"jack\"");
user.addStringProperty("address");
user.addStringProperty("teacher");
user.addIntProperty("age").primJavaType().defValue("17");
}
在3.0之后推⾏⽤注解和直接写Entity的写法,所以可以直接在Entity的类⾥指定
@Entity
public class Student {
@Id(autoincrement = true)
private long id; //主键
private String name;
private String schoolTime = "09-01"; //开学时间默认都是9⽉1⽇
private int age = 19; // 刚上⼤学的默认都是19岁
// 下⾯⽣成的getter 和setter省略。。。
}
2.数据库升级时给升级字段赋初始值
上⾯说的的数据库升级,是需要写⼀条alter table的sql语句,可以直接拼接到这⼀⾏后⾯
// 上⾯判断该列名是否存在
// ...
String sql = "alter table " + UserBookDao.TABLENAME +
" add COLUMN " + UserBookDao.lumnName + " INTEGER" + " NOT NULL DEFAULT(-1) "; // 直接拼接在语句最后董铂然博客园db.execSQL(sql);
// ...
注:以前听过⼀种说法是直接在UserDao这种⽣成的类⾥直接在⽣成的创建语句后⾯拼接DEFAULT,这⾥⾮常反对,⾸先⼈家类名明确表明 // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 并且有些⼈的代码可能设置的是⼿动⽣成,但我们的项⽬就在gradle⾥设置了每次build都会先⾃动⽣成⼀下,这种情况每次都会覆盖。
以上就是本⽂的全部内容,希望本⽂的内容对⼤家的学习或者⼯作能带来⼀定的帮助,同时也希望多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论