安卓GreenDao框架一些进阶用法整理

大致分为以下几个方面:

  1. 一些查询指令整理
  2. 使用SQL语句进行特殊查询
  3. 检测表字段是否存在
  4. 数据库升级
  5. 数据库表字段赋初始值

一、查询指令整理

1.链式执行的指令

return mDaoSession.getUserDao().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.条件里的指令

return mDaoSession.getUserDao().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.Properties.UserName.columnName + " FROM " + UserBookDao.TABLENAME
  + " ORDER BY "
  + UserBookDao.Properties.CreatedTime
  + " DESC "
  + " LIMIT "
  + page * LIMIT_NUM
  + " , "
  + LIMIT_NUM;

ArrayList<String> result = new ArrayList<>();
Cursor c = mDaoSession.getDatabase().rawQuery(queryString,new String[]{});
try {
 if (c != null) {
 if (c.moveToFirst()) {
  do {
  result.add(c.getString(0));
  } while (c.moveToNext());
 }
 }
} finally {
 if (c != null) {
 c.close();
 }
}

大概代码的画风就是这个样子,先拼接出一个符合sql语法的字符串,上面也随机加了一写其他的操作指令字段排序和分页,使得查询指令看上去更加完整,然后使用游标来接收上面的查询结果。

可能大多数查询的时候会带上一些参数,比如where XX = XX 的过滤条件,假设有个需求需要在之前的查询用户需求上加上对出版社和图书价格的限制,则查询方式如下

String queryString =
 "SELECT DISTINCT " + UserBookDao.Properties.UserName.columnName + " FROM " + UserBookDao.TABLENAME // 董铂然博客园
  + " WHERE "
  + UserBookDao.Properties.Publisher.columnName + " = ?"
  + " AND "
  + UserBookDao.Properties.Price.columnName + " > ?"
  + " ORDER BY "
  + UserBookDao.Properties.CreatedTime
  + " DESC ";

ArrayList<String> result = new ArrayList<>();
Cursor c = mDaoSession.getDatabase().rawQuery(queryString, new String[]{"某出版社"),
 String.valueOf(100.00)});
try {
 if (c != null) {
 if (c.moveToFirst()) {
  do {
  result.add(c.getString(0));
  } while (c.moveToNext());
 }
 }
} finally {
 if (c != null) {
 c.close();
 }
}

带上参数的查询字符串需要在上面使用问号占位,然后在下面用rawQuery带参数的api里填上相关的入参。

2. SELECT同时查询多个字段

还是用这个查书的例子,假设一下要查“书名”、“出版社”、“价格” 三个字段

String queryString = "SELECT "
 + UserBookDao.TABLENAME + "." + UserBookDao.Properties.BookName.columnName + ","
 + UserBookDao.TABLENAME + "." + UserBookDao.Properties.Publisher.columnName + ","
 + UserBookDao.TABLENAME + "." + UserBookDao.Properties.Price.columnName + " "
 + "FROM "
 + UserBookDao.TABLENAME + " "
 + "WHERE"
 + UserBookDao.Properties.Price + " > 100.00 ";
Cursor cursor = null;
try {
 cursor = session.getDatabase().rawQuery(queryString,new String[]{});
 if (cursor == null) {
 return payMap;
 }
 // 取出三个字段分别对应的索引,下面再对着索引去取值
 int nameIndex = cursor.getColumnIndex(UserBookDao.Properties.BookName.columnName);
 int publisherIndex = cursor.getColumnIndex(UserBookDao.Properties.Publisher.columnName);
 int priceIndex = cursor.getColumnIndex(UserBookDao.Properties.Price.columnName);
 if (nameIndex != -1 && publisherIndex != -1 && priceIndex != -1) {
 while (cursor.moveToNext()) {
  String name = cursor.getString(nameIndex);
  String publisher = cursor.getString(publisherIndex);
  Double price = cursor.getDouble(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 && cursor.getColumnIndex(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.Properties.Author.columnName)) {
  String sql = "alter table " + UserBookDao.TABLENAME +
   " add COLUMN " + UserBookDao.Properties.Author.columnName + " TEXT";
  db.execSQL(sql);
  }
  if (!hasColumn(db, UserBookDao.TABLENAME, UserBookDao.Properties.Type.columnName)) {
  String sql = "alter table " + UserBookDao.TABLENAME +
   " add COLUMN " + UserBookDao.Properties.Type.columnName + " INTEGER";
  db.execSQL(sql);
  }
 }
 }
}

除了上面的修改表,如果改动太多或是换了表明,还可以直接删了重建(这么做的话之前的数据也就删了)

if (oldVersion < 3) {
 UserDao.dropTable(new StandardDatabase(db),true);
 UserStudentDao.createTable(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.Properties.Type.columnName + " INTEGER" + " NOT NULL DEFAULT(-1) "; // 直接拼接在语句最后 董铂然博客园
db.execSQL(sql);
// ...

注:以前听过一种说法是直接在UserDao这种生成的类里直接在生成的创建语句后面拼接DEFAULT,这里非常反对, 首先人家类名明确表明 // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.  并且有些人的代码可能设置的是手动生成,但我们的项目就在gradle里设置了每次build都会先自动生成一下,这种情况每次都会覆盖。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • GreenDao 3.2.0 的基本使用

    前言 Android开发中我们或多或少都会接触到数据库.Android中提供了一个占用内存极小的关系型数据库-SQLite.虽然Android系统中提供了许多操作SQLite的API,但是我们还是需要手动去编写SQL语句,这经常会出现一些莫名其妙的问题(

  • 安卓GreenDao框架一些进阶用法整理

    大致分为以下几个方面: 一些查询指令整理 使用SQL语句进行特殊查询 检测表字段是否存在 数据库升级 数据库表字段赋初始值 一.查询指令整理 1.链式执行的指令 return mDaoSession.getUserDao().queryBuilder(). XXX. XXX. XXX. list(); 一般的查询语句会在中间xxx的位置加上各种判断和过滤的方法指令,除了最后的终结指令list()或unique()返回的是集合或业务对象,其他的都是返回QueryBuilder对象,大多数情况下XX

  • CI框架附属类用法分析

    本文实例讲述了CI框架附属类用法.分享给大家供大家参考,具体如下: 有些时候,你可能想在你的控制器之外新建一些类,但同时又希望 这些类还能访问 CodeIgniter 的资源 任何在你的控制器方法中初始化的类都可以简单的通过 get_instance() 函数来访问 CodeIgniter 资源.这个函数返回一个 CodeIgniter 对象. 通常来说,调用 CodeIgniter 的方法需要使用 $this $this->load->helper('url'); $this->loa

  • Laravel框架验证码类用法实例分析

    本文实例讲述了Laravel框架验证码类用法.分享给大家供大家参考,具体如下: 在Laravel中有很多图片验证码的库可以使用,本篇介绍其中之一:gregwar/captcha,这个库比较简单,在Laravel中比较常用.下面我们就来介绍下使用细节: 首先, composer.json中如下加入配置: "require": { ... "gregwar/captcha": "1.*" }, 然后,已成习惯的命令: composer update

  • thinkPHP框架动态配置用法实例分析

    本文实例讲述了thinkPHP框架动态配置用法.分享给大家供大家参考,具体如下: 最近在用@ThinkPHP 做系统的时候,要用到一个功能,就要动态的将系统的配置参数保存到Config文件中.以往,我们做系统的时候,项目的配置参数都会直接事先写入到Config/Config.php文件中,然后在项目中应用即可.但是,有些项目,用户需要根据自己的情况将配置参数,通过后台动态的来设置.这种动态的参数配置,一般我们有两种方式,一种是写入到数据库,另一种就是写入到配置文件.今天,我来说说用配置文件的形式

  • flask框架视图函数用法示例

    本文实例讲述了flask框架视图函数用法.分享给大家供大家参考,具体如下: flask框架 视图函数当中 各种实用情况简单配置 1 建立连接 2 路由参数 3 返回网络状态码 4 自定义错误页面 5 重定向 6 正则url限制 和 url 优化 7 设置和获取cookie #coding:utf8 # 导入flask from flask import Flask,abort,redirect,make_response,request from werkzeug.routing import

  • Python爬虫框架Scrapy基本用法入门教程

    本文实例讲述了Python爬虫框架Scrapy基本用法.分享给大家供大家参考,具体如下: Xpath <html> <head> <title>标题</title> </head> <body> <h2>二级标题</h2> <p>爬虫1</p> <p>爬虫2</p> </body> </html> 在上述html代码中,我要获取h2的内容,

  • Laravel5.1 框架响应基本用法实例分析

    本文实例讲述了Laravel5.1 框架响应基本用法.分享给大家供大家参考,具体如下: 上篇笔记刚刚记录完请求 这节就来说说响应,一般来说啊 一个请求对应一个响应,用户都请求咱了 咱必须做一些逻辑后给人家反馈是不是,这就是响应. 1 基本的响应 我们前几篇笔记已经用过很多响应了,其中包括字符串: Route::get('/', function () { return '欢迎欢迎'; }); 注:我们写的是返回简单的字符串,但是Laravel框架会自动把它组成一个响应. 1.1 自定义响应头 R

  • Laravel5.1 框架控制器基础用法实例分析

    本文实例讲述了Laravel5.1 框架控制器基础用法.分享给大家供大家参考,具体如下: 为什么要使用控制器 像我们之前写一些逻辑呢都是在Route(路由)中,搞得Route文件特别庞大,其实我们应该把这些逻辑都抽到一个控制器里,路由分发后到控制器,控制器做相应的操作,比如关于后台的逻辑应该抽到AdminController中,Route文件只管分发. 1 如何创建一个控制器 1.1.1 创建RESTful控制器 至于什么是RESTful?自行百度- -,我先简单说下,它里面自动填充了一些增删改

  • Laravel5.1框架路由分组用法实例分析

    本文实例讲述了Laravel5.1框架路由分组用法.分享给大家供大家参考,具体如下: 路由分组有啥好处? 有时候啊 一大堆路由它们都有共同的地方,比如都使用一个中间件(过两天写)或是前缀都一样,避免代码重复 我们可以将他们分到一组中. 1 路由分组可以共享哪些属性? 中间件 middleware. 控制器的命名空间 namespace. 子域名 domain 路由前缀 1.1 中间件 关于中间件大K还没有写笔记介绍,这里先简单说下 中间件就是接收到请求后验证一些东西或相应后验证一些东西,比如La

  • python orm 框架中sqlalchemy用法实例详解

    本文实例讲述了python orm 框架中sqlalchemy用法.分享给大家供大家参考,具体如下: 一.ORM简介 1. ORM(Object-Relational Mapping,对象关系映射):作用是在关系型数据库和业务实体对象之间做一个映射. 2. ORM优点: 向开发者屏蔽了数据库的细节,使开发者无需与SQL语句打交道,提高了开发效率; 便于数据库的迁移,由于每种数据库的SQL语法有差别,基于Sql的数据访问层在更换数据库时通过需要花费时间调试SQL时间,而ORM提供了独立于SQL的接

随机推荐