GreenDAO 3.2.2 简单入门(一)增删改查

前言

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'
GreenDAO配置一.png

步骤二

打开module下的build.gradle,即app/build.gradle,添加以下内容:

apply plugin: 'org.greenrobot.greendao'
implementation 'org.greenrobot:greendao:3.2.2'

GreenDAO配置二.png

接着sync now项目。

步骤三

继续在module下的build.gradle中添加配置代码:

// 示例
greendao {
    // value可以根据自身需求更改
    // 数据库版本
    schemaVersion 3
    // 生成DAO、DaoMaster、DaoSeesion的包名
    daoPackage 'com.jwstudio.greendao.gen'
    // 生成DAO、DaoMaster、DaoSeesion的目录
    targetGenDir 'src/main/java'
}

GreenDAO配置三.png

然后sync now。如果你没有添加上述配置,在make project后,XxxDaoDaoMasterDaoSeesion(它们在接下来的内容中会进行简单介绍)会存放在如下图所示的目录下:
GreenDAO配置四.png

若你添加了上述的配置,make project后你就明白了。注意,目前还不用make project

准备

下图是demo的目录结构:


demo目录结构.png

在GreenDAO中,一个实体类就对应的一个表,通过注解的方式关联起来。下面是一些常用注解的介绍。

  • @Entity
    • nameInDb:在数据库中表名,默认是实体类名
    • indexes:为指定的列设置索引,排列时降序还是升序
    • createInDb:是否在数据库中创建数据表,默认为true,即自动创建表
    • active:是否为激活状态,默认为false,非激活状态要通过DAO方法操作
  • @Id:将该属性设置为主键,且该属性为Long型,对应表中的_id主键
    • autoincrement:设置为true表示主键为自动增长
  • @Index:为属性设置索引
    • name:索引名
    • uniquetrue表示唯一索引
  • @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类,能够创建和删除表
    • 其内部类OpenHelperDevOpenHelper,是创建SQLite数据库的SQLiteOpenHelper的具体实现
  • DaoSession
    • 管理所有的Dao对象
    • 对实体类进行增删该查等操作
    • 跟踪和管理查询缓存,提高查询效率
  • DAOS(如UserDao类)
    • 能够持久访问和查询实体类
    • DaoSession有更加丰富的增删查改方法

接下来我们来看下UserDao类中一段代码:

UserDao代码片段.png

可以得到,没用注解的属性在表中的列名默认为全大写,如usercode属性对应USERCODE;若属性采用驼峰命名法,如userAddress对应USER_ADDRESS;若添加了@Property注解,以nameInDb属性的值为准。另外,添加了@Transient注解的属性并没有生成。

UserDao类中还自动生成了创建表的SQL语句,而增删查改的方法定义在其父类AbstractDao中。

假如再新建一个Student的实体类,make project后在com.jwstudio.greendao.gen包下会生成对应的StudentDao类,并且DaoMasterDaoSession也会添加相应的代码,即有多少个实体类,经过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 简单入门(三)数据库升级

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容