前言
greenDAO是一款轻巧快捷的Android版ORM,可将对象映射到SQLite数据库。greenDAO针对Android进行了高度优化,性能卓越,占用内存极少。
GreenDAO源码下载
GreenDAO配置
可以点击上述的网址查看GreenDAO最新版本和文档入口,以及如何为本地项目添加依赖。目前,其最新版本是3.2.2。
步骤一
打开Project下的build.gradle
,注意不是module下的build.gradle
,添加以下内容:
mavenCentral()
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
步骤二
打开module下的build.gradle
,即app/build.gradle
,添加以下内容:
apply plugin: 'org.greenrobot.greendao'
implementation 'org.greenrobot:greendao:3.2.2'
接着
sync now
项目。
步骤三
继续在module下的build.gradle
中添加配置代码:
// 示例
greendao {
// value可以根据自身需求更改
// 数据库版本
schemaVersion 3
// 生成DAO、DaoMaster、DaoSeesion的包名
daoPackage 'com.jwstudio.greendao.gen'
// 生成DAO、DaoMaster、DaoSeesion的目录
targetGenDir 'src/main/java'
}
然后
sync now
。如果你没有添加上述配置,在make project
后,XxxDao
、DaoMaster
、DaoSeesion
(它们在接下来的内容中会进行简单介绍)会存放在如下图所示的目录下:若你添加了上述的配置,
make project
后你就明白了。注意,目前还不用make project
。
准备
下图是demo的目录结构:
在GreenDAO中,一个实体类就对应的一个表,通过注解的方式关联起来。下面是一些常用注解的介绍。
-
@Entity
-
nameInDb
:在数据库中表名,默认是实体类名 -
indexes
:为指定的列设置索引,排列时降序还是升序 -
createInDb
:是否在数据库中创建数据表,默认为true
,即自动创建表 -
active
:是否为激活状态,默认为false
,非激活状态要通过DAO方法操作
-
-
@Id
:将该属性设置为主键,且该属性为Long
型,对应表中的_id
主键-
autoincrement
:设置为true
表示主键为自动增长
-
-
@Index
:为属性设置索引-
name
:索引名 -
unique
:true
表示唯一索引
-
-
@Property
:设置该属性在数据库表中的列名-
nameInDb
:设置列名
-
-
@NotNull
:非空 -
@Transient
:表示此属性时临时存储,不会被存储到表中,即这个属性将不会作为数据表中国的一个字段
新建一个User
类,内容 如下:
@Entity(
nameInDb = "USERS", // 表名
indexes = {
@Index(value = "name DESC"), // 为属性name设置索引
}
)
public class User {
@Id(autoincrement = true) // 主键,要求是Long型
private Long id;
@Index(name = "usercode_index", unique = true) // 设置索引且是唯一索引
private String usercode;
@Property(nameInDb = "username") // 设置该属性对应的列名
@NotNull // 非空
private String name;
private String userAddress; // 可以为空
@Transient // 临时存储
private int tempUserSign;
}
然后make project
。成功后User
类会多出一些方法,读者不要随意改动就行了。另外,项目下也多出了一个包,也就是之前在module下添加的greendao{}
配置的效果,以及相应的类。以下是它们的简单介绍:
-
DaoMaster
类- 是GreenDAO的入口,也是GreenDAO顶级对象
- 拥有SQLite数据库对象
- 能够管理DAO类,能够创建和删除表
- 其内部类
OpenHelper
与DevOpenHelper
,是创建SQLite数据库的SQLiteOpenHelper
的具体实现
-
DaoSession
类- 管理所有的Dao对象
- 对实体类进行增删该查等操作
- 跟踪和管理查询缓存,提高查询效率
- DAOS(如
UserDao
类)- 能够持久访问和查询实体类
- 比
DaoSession
有更加丰富的增删查改方法
接下来我们来看下UserDao
类中一段代码:
可以得到,没用注解的属性在表中的列名默认为全大写,如
usercode
属性对应USERCODE
;若属性采用驼峰命名法,如userAddress
对应USER_ADDRESS
;若添加了@Property
注解,以nameInDb
属性的值为准。另外,添加了@Transient
注解的属性并没有生成。
UserDao
类中还自动生成了创建表的SQL语句,而增删查改的方法定义在其父类AbstractDao
中。
假如再新建一个Student
的实体类,make project
后在com.jwstudio.greendao.gen
包下会生成对应的StudentDao
类,并且DaoMaster
、DaoSession
也会添加相应的代码,即有多少个实体类,经过make project
后就有DAO类与之对应。
创建HMROpenHelper
类,代码如下:
public class HMROpenHelper extends DaoMaster.OpenHelper {
public HMROpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
}
创建MyGreenDAOApplication
类,并在AndroidManifest.xml
中的application
标签下添加android:name
属性,android:name=".MyGreenDAOApplication"
,其代码如下:
public class MyGreenDAOApplication extends Application {
private SQLiteDatabase db;
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
public static MyGreenDAOApplication instances;
@Override
public void onCreate() {
super.onCreate();
instances = this;
setDatabase();
}
// GreenDAO各应用对象的初始化
private void setDatabase() {
// 创建数据库
HMROpenHelper mHelper = new HMROpenHelper(this, "myGDDb", null);
db = mHelper.getWritableDatabase();
mDaoMaster = new DaoMaster(db);
mDaoSession = mDaoMaster.newSession();
}
public static MyGreenDAOApplication getInstances() {
return instances;
}
public SQLiteDatabase getDb() {
return db;
}
public DaoMaster getmDaoMaster() {
return mDaoMaster;
}
public DaoSession getmDaoSession() {
return mDaoSession;
}
}
初始化
public class MainActivity extends AppCompatActivity {
private UserDao userDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取UserDao对象
userDao = MyGreenDAOApplication.getInstances().getmDaoSession().getUserDao();
}
// 打印数据库表中的记录
private void queryList() {
String result = "显示结果为:";
// 获得表中的所有记录
List<User> users = userDao.loadAll();
int i = 0;
for (User user : users) {
i++;
String res = result + "i=" + i + ",id:" + user.getId() + ",name:" + user.getName() + ",address:" + user.getUserAddress();
Log.d("TAG", res);
}
}
}
添加记录
-
long insert(T entity)
:插入指定实体,entity即实体对象 -
void insertInTx(T... entities)
:插入多个实体,参数可为List集合 -
long insertOrReplace(T entity)
:插入或替换指定实体 -
void insertOrReplaceInTex(T... entities)
:插入或替换指定实体,参数可为List集合
单条记录添加
private void insterOne() {
User user1 = new User();
user1.setName("孙悟空");
user1.setUsercode("001");
user1.setUserAddress("花果山水帘洞");
userDao.insert(user1);
}
// onCreate()方法的代码更改如下
userDao.deleteAll();// 删除表中所有记录,保持表中的数据记录纯净,在此便于演示;按需添加
insterOne();
queryList() ;
多条记录添加
private void insertMany() {
List<User> users = new ArrayList<>();
User user1 = new User();
user1.setName("孙悟空");
user1.setUsercode("001");
user1.setUserAddress("花果山水帘洞");
User user2 = new User();
user2.setName("猪八戒");
user2.setUsercode("002");
user2.setUserAddress("高老庄");
User user3 = new User();
user3.setName("沙悟净");
user3.setUsercode("003");
user3.setUserAddress("流沙河");
User user4 = new User();
user4.setName("黑熊怪");
user4.setUsercode("004");
user4.setUserAddress("黑风山");
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
userDao.insertInTx(users);
}
// onCreate()方法的代码更改如下
userDao.deleteAll();// 保持表中的数据记录纯净,在此便于演示;按需添加
insterMany();
queryList() ;
删除
-
void delete(T entity)
:删除指定的实体 -
void deleteInTx(T... entities)
:删除多个实体,参数可以是List集合 -
void deleteAll()
:删除所有记录 -
void deleteByKey(K key)
:删除指定主键对应的实体
private void deleteByName(){
QueryBuilder qb=userDao.queryBuilder();
// 查询想要删除的记录;根据场景需要,记得判空
List<User> userList=qb.where(UserDao.Properties.Name.eq("猪八戒")).list();
for(User user:userList){
// 每次删除一条记录
userDao.delete(user);
}
// 一次删除多条记录
// userDao.deleteInTx(userList);
}
// onCreate()方法的代码更改如下
userDao.deleteAll();// 保持表中的数据记录纯净,在此便于演示;按需添加
insterMany();
deleteByName();
queryList() ;
修改
-
void update(T entity)
:修改一个被查询出来的实体 -
void updateInTx(T... entities)
:修改多个被查询出来的实体,这些实体可被放在一个List中
private void updateUser(){
User user=userDao.queryBuilder().where(UserDao.Properties.Name.eq("孙悟空")).build().unique();
// 修改使用setter方法
user.setUserAddress("天宫蟠桃园");
userDao.update(user);
}
// onCreate()方法的代码更改如下
userDao.deleteAll();// 保持表中的数据记录纯净,在此便于演示;按需添加
insterMany();
updateUser();
queryList() ;
查询
DAO查询
-
java.util.List<T> loadAll
:查找所有记录,返回List集合 -
T load(K key)
:按主键值查询一条记录,返回实体类对象 -
T loadByRowId(long rowId)
:按行id查询一条记录,返回实体类对象
注意: - 如果主键
id
是自动增长。则load()
方法和loadByRowId()
方法作用相同,即key
值与rowId
值相同 -
list()
方法返回所有值,unique()方法返回唯一值
private void loadOneById() {
// 要注意”6“是否存在
// User user = userDao.load(new Long((long) 6));
User user = userDao.loadByRowId(new Long((long) 6));
Log.d("TAG", "name:" + user.getName());
}
// onCreate()方法的代码更改如下
userDao.deleteAll();// 保持表中的数据记录纯净,在此便于演示;按需添加
insterMany();
loadOneById();
QueryBuilder查询
-
QueryBuilder<T> where(WhereCondition cond, whereCondition... condMore)
:条件查询,参数之间本质是AND连接 -
QueryBuilder<T> whereOr(WhereCondition cond, whereCondition... condMore)
:条件查询,参数之间本质是OR连接 -
QueryBuilder<T> distinct()
:去除重复记录,例如使用联合查询时 -
QueryBuilder<T> limit(int limit)
:限制记录返回数,用于分页 -
QueryBuilder<T> offset(int offset)
:偏移结果起始位,即从第几条开始取limit()
中限制的记录数,配合limit()
使用 -
QueryBuilder<T> orderAsc(Property... properties)
:升序排列 -
QueryBuilder<T> orderDesc(Property... properties)
:降序排列 -
WhereCondition and(WhereCondition cond1, WhereCondition cond2, whereCondition... condMore)
:添加条件,AND连接 -
WhereCondition or(WhereCondition cond1, WhereCondition cond2, whereCondition... condMore)
:添加条件,OR连接
private void queryQB() {
QueryBuilder qb = userDao.queryBuilder();
// 查询名字带有“悟”字的,并且按照属性usercode进行降序排列
// List<User> userList=qb.where(UserDao.Properties.Name.like("%悟%"))
// .orderDesc(UserDao.Properties.Usercode).list();
//查询名字带有“悟”字的,而且地址时“流沙河”的或者是带有“山”字的且usercode==001的
List<User> users = qb.where(UserDao.Properties.Name.like("%悟%"),
qb.or(UserDao.Properties.UserAddress.eq("流沙河"),
qb.and(UserDao.Properties.UserAddress.like("%山%"),
UserDao.Properties.Usercode.eq("001")))).list();
if (users != null) {
int i = 0;
for (User user : users) {
i++;
String res = "i=" + i + ",id:" + user.getId() + ",name:" + user.getName() + ",address:" + user.getUserAddress();
Log.d("TAG", res);
}
}
}
// 按名字查询
private void queryOneByName() {
User user = userDao.queryBuilder().where(UserDao.Properties.Name.eq("孙悟空")).build().unique();
if (user != null) {
tvResult.setText("添加一条记录:id:" + user.getId() + ",地址:" + user.getUserAddress());
}
}
// 分页示例
// limit(3):查询3条记录,offset(1):从第2条记录开始,0表示从第一条记录开始
// 可用于分页,即limit(3)表示一页有3条记录,可用于显示一页的记录
List<User> users = userDao.queryBuilder().limit(3).offset(1).list();
Query重复查询
-
Query<T> build()
:获得Query对象 -
Query<T> setParameter(int index, java.lang.Object parameter)
:设置查询参数
private void queryRepeat(){
Query query=userDao.queryBuilder().where(UserDao.Properties.Name.like("%悟%"),
UserDao.Properties.UserAddress.like("%山%")).build();
// 重新设置参数
query.setParameter(0,"%怪%");
query.setParameter(1,"%洞%");
List<User> userList=query.list();
}
SQL查询
-
java.util.List<T> queryRaw(java.lang.String where, java.lang.String... selectionArg)
:直接用sql语句获得查询List对象 -
Query<T> queryRawCreate((java.lang.String where, java.lang.Object... selectionArg)
:获得Query对象,Query.list()获得List对象
注意:sql语句中的列名是数据表列名,而不是实体类的属性名。
private void querySql(){
// List<User> userList=userDao.queryRaw("where username like '%悟%'");
Query query=userDao.queryRawCreate("where username like '%悟%'");
List<User> userList=query.list();
queryView(userList);
}
补充
-
eq
:==(等于) -
notEq
:!=(不等于) -
gt
:>(大于) -
It
:<(小于) -
ge
:>=(大于等于) -
le
:<=(小于等于) -
like
:包含,需要与%(_)配合使用 -
between
:在两者之间 -
in
:在某些值内 -
notIn
:不在某些值内
注意:在代码中加入以下两行代码,即可在Android Monitor窗口中看到生成的sql语句,以及sql语句中的值。
// 在onCreate()中添加
QueryBuilder.LOG_SQL = true; // 显示sql语句
QueryBuilder.LOG_VALUES = true; // 显示sql语句中的值
总结
拥有SQL基础,有利于理解GreenDAO的API,也能更好地运用。在增删改查中,查询是最复杂的,毕竟在开发中查询时用的最多的,也是最难用的,需要多动手实战才能掌握。
最终源码
GreenDAO 3.2.2 简单入门(二)多表查询和多表关联
GreenDAO 3.2.2 简单入门(三)数据库升级