GreenDao3.2数据库使用教程

greenDao github地址

相关gradle配置

// 根目录下 build.gradle 文件:
buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}

// app项目 build.gradle 文件:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin

android {
  //...其他相关配置
  //...compileSdkVersion / buildToolsVersion

  //数据库配置项[必填]      
  greendao {
        schemaVersion 1 //数据库版本号
        daoPackage 'com.micro.testgreengao.greendao.gen'  //自动生成的工具类包名
        targetGenDir 'src/main/java'  //自动代码生成路径
  }  
}


dependencies {
    compile 'org.greenrobot:greendao:3.2.2' // add library
}

可参考配置:点这里

基本增删改查命令【CRUD】

新建User.java文件,如下:

@Entity
public class User {

    @Id(autoincrement = true)
    @Property(nameInDb = "_id")
    private Long _id ;

    @Property(nameInDb = "_name" )
    private String name ;

    @Property(nameInDb = "_age")
    private int age ;

    @Generated()
    public User() {}

这里声明一下,各种注解稍后解释,大家先看着就行,User的属性getter/setter方法不需要你生成,使用Ctrl+F9(或者Build -> make module)进行编译,然后在你所写的greendao/package路径下生成了三个文件:UserDao,DaoMaster,DaoSession,如下图(其他文件无视即可):
GreenDao3.2数据库使用教程_第1张图片

同时再回过头来,你会发现你的User.java文件也生成了getter/setter方法,那么说明自动生成已经凑效了。

下面就greenDao的注解,简单说明一下各个注解的含义:

@Entity         标识实体类,greenDAO会映射成sqlite的一个表,表名为实体类名的大写形式

@Id             标识主键,该字段的类型为long或Long类型,autoincrement设置是否自动增长

@Property       标识该属性在表中对应的列名称, nameInDb设置名称

@Transient      标识该属性将不会映射到表中,也就是没有这列

@NotNull        设置表中当前列的值不可为空

@Convert        指定自定义类型(@linkPropertyConverter)

@Generated      greenDAO运行所产生的构造函数或者方法,被此标注的代码可以变更或者下次运行时清除

@Index          使用@Index作为一个属性来创建一个索引;定义多列索引(@link Entity#indexes())

@JoinEntity     定义表连接关系

@JoinProperty   定义名称和引用名称属性关系

@Keep           注解的代码段在GreenDao下次运行时保持不变  1.注解实体类:默认禁止修改此类 2.注解其他代码段,默认禁止修改注解的代码段

@OrderBy        指定排序

@ToMany         定义与多个实体对象的关系

@ToOne          定义与另一个实体(一个实体对象)的关系

@Unique         向数据库列添加了一个唯一的约束

注解需要在实际中运用,光这个我也是记不住的,写多了自然就记住了。

编写dao处理对象:

DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(ctx,DB_NAME);
DaoMaster mDaoMaster = new DaoMaster(devOpenHelper.getWritableDb());
DaoSession mDaoSession = mDaoMaster.newSession();

具体代码可以参考这里;

新增操作

    public void addData(User user) {
        UserDao userDao = mDaoSession.getUserDao();
        long insertId = userDao.insert(user);
        LogUtils.d("insertId:"+insertId);
    }

注意,User的初始化为:

User user = new User(null,"zhangsan",18);

User的Id应该设置为null,不然id默认为0,在自增主键情况下,插入数据将会报错。
同时还有以下方法:

  userDao.insertWithoutSettingPk(user);  //如果没有对象没有设置主键,使用这个方法,你基本上放进去的东西就废了,因为不知道怎么找出来:)
  userDao.insertOrReplace(user);   //如果主键一致,则替换为新的User对象
  userDao.insertInTx(List);  //批量插入User对象

删除

    public void deleteUser(long _id) {
        UserDao userDao = mDaoSession.getUserDao();
        userDao.deleteByKey(_id);
        LogUtils.d("delete User finished");
    }

上面是使用primary_key删除的,还有以下删除方式:

userDao.deleteAll();                              //删除全部
userDao.deleteByKeyInTx(List idList);       //删除id为idList中的User
userDao.deleteInTx(List userList);          //删除集合中的user
userDao.delete(user);                             //删除目标User[需要包含主键]

还可以使用条件删除,使用StringCondition模式,删除name=micro和age>20岁的人

QueryBuilder queryBuilder = mDaoSession.queryBuilder(User.class);;

WhereCondition.StringCondition  stringCondition = 
                    new WhereCondition.StringCondition("_name = 'micro'");
WhereCondition.StringCondition stringCondition1 = 
                    new WhereCondition.StringCondition("_age > 20");

queryBuilder.where(stringCondition,stringCondition1).
             buildDelete().executeDeleteWithoutDetachingEntities();

删除name=micro 或者 name>20的user

queryBuilder.whereOr(stringCondition,stringCondition1).buildDelete().executeDeleteWithoutDetachingEntities();

当然还可以使用Property进行删除:

        QueryBuilder queryBuilder = mDaoSession.queryBuilder(User.class);

        WhereCondition nameCondition = null ;
        WhereCondition ageCondition = null;
        Property[] properties = mDaoSession.getUserDao().getProperties();

        for (Property p : properties) {
            if(p.columnName.equals("_name")) {
                nameCondition = p.eq("micro");
            }

            if(p.columnName.equals("_age")){
                ageCondition = p.gt(20);
            }
        }

        queryBuilder.whereOr(nameCondition,ageCondition).
                    buildDelete().executeDeleteWithoutDetachingEntities();

基本套路是一致的。

修改
基本代码如下:

    public void updateUser(User user) {
        UserDao userDao = mDaoSession.getUserDao();
        userDao.update(user);
        LogUtils.d("update user finished");
    }

这里User中需要有主键,不然没法修改的。
当然还有

userDao.updateInTx(Iterator);    //批量修改User

查找
这个查找是SQL中最复杂最难的一个科目,也是考验程序员经验的时候,面对大数据量的数据库,一条有经验的SQL往往能节省很多时间,到了我们android这里,就不扯了,greenDao已经做了很好的优化了,你只需要怎么查找就行了。

通过Id查找
这个最简单了,就不说了,代码为:

    public void btnGetById(View view) {
        User user = mDaoSession.load(User.class,2L);
        if(null != user) {
            mTvInfo.setText(user.toString());
        }else{
            Toast.makeText(this, "查询数据失败", Toast.LENGTH_SHORT).show();
        }
    }

通过原生SQL查找
这个一般在条件语句中用的比较多:

    public void btnGetBySQL(View view) {
        String sql = "select * from " + UserDao.TABLENAME + " where _age > ? "  ;

        Cursor cursor =  mDaoSession.getDatabase().rawQuery(sql,new String[]{String.valueOf(23)});
        while (null != cursor && cursor.moveToNext()) {
            Long _id =  cursor.getLong(cursor.getColumnIndex("_id"));
            String name = cursor.getString(cursor.getColumnIndex("_name")) ;
            int age = cursor.getInt(cursor.getColumnIndex("_age"));
            //..... 原生的SQLite写法
        }
}

通过StringCondition查找
这个其实也说过了,就是上面的删除项,其实删除就是你先查出来再删除啊:

    public void btnGetByStringCondition(View view) {
        QueryBuilder queryBuilder = mDaoSession.queryBuilder(User.class);

        WhereCondition.StringCondition  stringCondition = 
                                new WhereCondition.StringCondition("_name = 'micro'");
        WhereCondition.StringCondition stringCondition1 = 
                                new WhereCondition.StringCondition("_age > 20");

        List userList = queryBuilder.where(stringCondition,stringCondition1).
                              build().list();

        Log.d("TAG","---->>>" + userList);
    }

通过PropertyCondition查找

QueryBuilder queryBuilder = mDaoSession.queryBuilder(User.class);

WhereCondition nameCondition = null ;
WhereCondition ageCondition = null;
Property[] properties = mDaoSession.getUserDao().getProperties();

for (Property p : properties) {
     if(p.columnName.equals("_name")) {
         nameCondition = p.eq("micro");  
         //p.eq,p.nep,p.like,p.between,p.in,p.notIn,p.isNull,p.isNotNull 各种SQL操作
     }

     if(p.columnName.equals("_age")){
        ageCondition = p.gt(20);
     }
}
    List userList = queryBuilder.where(queryBuilder.or(nameCondition,ageCondition)).build().list();

数据库关系模型

目前greenDao支持的数据库模型为一对比一,一对多模型,暂未支持多对多模型。这是这篇博客的重点所在,在项目中,遇到几张表,没什么逻辑关系,那么使用原生的SQLite就可以搞定了,就不比请greenDao大佬了。由于在项目中遇到了很多表出现了相互依赖的关系,那么使用greenDao简单配置一下,就可以使用了。

一对一关系
什么是一对一,读官方的解释我不会,就举个例子吧,每个人对应一张身份证信息,那么提取对象人与身份证 就是一对一的关系。在greenDao中,建立这种一对一的关系,先要确定谁是主导关系,这里是人,因为有人才有身份证信息,那么看IdCard和Person对象:

IdCard对象

@Entity
public class IdCard {

    @Id(autoincrement = true)
    private Long _id ;

    private String cardName;

    private String location;


    @Generated()
    public IdCard() {
    }
}

Person对象

@Entity
public class Person {

    @Id(autoincrement = true)
    private Long _id;

    private String name ;

    private Long idCardId ;

    @ToOne(joinProperty = "idCardId")
    private IdCard  idCard;

    @Generated
    public Person(){}

}

可以看到,Person对象中存在了IdCard的引用,而且IdCard的注解上为@ToOne,而其中的joinProperty对应了Person中一个私有属性idCardId。
完成编译之后,我们可以打开greenDao给我们建立的数据库,其中Person与IdCard表的结构为:

GreenDao3.2数据库使用教程_第2张图片

我们看到了Person表里面引用了IdCard的id,那么添加数据时应该这样:

    public void addPersonAndIdCard(View view) {
        IdCard idCard = new IdCard(null,"421111111133","shanghai22");
        mDaoSession.getIdCardDao().insert(idCard);

        Person p = new Person(null,"lisi",null);
        p.setIdCard(idCard);
        Long insertId = mDaoSession.getIdCardDao().getPersonDao().insert(p);

        Toast.makeText(this, "the insert id is " + insertId, Toast.LENGTH_SHORT).show();
    }

结果为:



一对多关系

对于一对多关系,这个字面上很好解释,一个人可以拥有多套房子,一个人可以买多件商品,水有不同的状态等等。在greenDao中,有三种映射方式生成一对

第一种:
@ToMany(referencedJoinProperty = “referenceId”)

一个人可有多个产品订单,抽象之后产生:顾客Customer与订单Order对象。一个顾客对应多个订单:
Order.java:

@Entity(nameInDb = "t_order"public class Order {

    @Id
    private Long _id ;

    private java.util.Date date ;

    //引用了顾客的Id
    private long customerId ;

    @Generated()
    public Order() {
    }

Customer.java:

@Entity
public class Customer {

    @Id
    private Long id ;

    @ToMany(referencedJoinProperty = "customerId")
    @OrderBy("date ASC")
    private List orders;

    @Generated()
    public Customer() {
    }

在Custom中使用注解@ToMany, 其referencedJoinProperty 对应Order对象中的customerId 对应的多个订单为List类型,生成的表的结构为:

GreenDao3.2数据库使用教程_第3张图片

插入数据:

    public void btnAdd(View view) {
        CustomerDao customerDao = mSession.getCustomerDao();

        Customer customer = new Customer(null);
        customerDao.insert(customer);

        OrderDao orderDao = mSession.getOrderDao();

        Order order1 = new Order(null,new Date(),customer.getId());
        Order order2 = new Order(null,new Date(),customer.getId());
        Order order3 = new Order(null,new Date(),customer.getId());

        orderDao.insert(order1);
        orderDao.insert(order2);
        orderDao.insert(order3);

        Toast.makeText(this, "add data finished...", Toast.LENGTH_SHORT).show();
    }

GreenDao3.2数据库使用教程_第4张图片

第二种:
@ToMany(joinProperties = {
@JoinProperty(name = “current_object_param”,referencedName = “reference_object_params”)
})

什么意思呢?不好解释,那还是举个例子吧,比如一个成功的人SuccessfulMan拥有很多家公司,抽象出来,这个SuccessfulMan对应多个公司对象,那么相对应的对象分别为:

SuccessFulMan.java

@Entity
public class SuccessfulMan {

    @Id(autoincrement = true)
    private Long _id;

    private int age ;

    @NotNull
    private String name;

    @ToMany(joinProperties = {
       @JoinProperty(name = "name",referencedName = "successfulManName")
    })
    @OrderBy("date ASC")
    private List companyList;

    @Generated()
    public SuccessfulMan (){}

}

Company.java:

@Entity
public class Company {

    @Id(autoincrement = true)
    private Long _id;

    @NotNull
    private String successfulManName ;

    //当前公司名称
    private String companyName ;

    private java.util.Date date ;

    //销售额
    private double price;

    @Generated()
    public Company(){}
}

编译成功之后,我们查看两张表的结构:

GreenDao3.2数据库使用教程_第5张图片

SuccessfulMan表中的name字段与Company表中的successful_man_name绑定了,我们来添加数据试一下:

    public void addBtn(View view) {
        SuccessfulMan man = new SuccessfulMan(null, "micro", 34);
        mDaoSession.getSuccessfulManDao().insert(man);

        Company company = new Company(null, "micro", "baidu1", new Date(), 2000);
        Company company2 = new Company(null, "micro", "tencent1", new Date(), 4000);
        Company company3 = new Company(null, "micro", "ali1", new Date(), 5000);

        mDaoSession.getCompanyDao().insert(company);
        mDaoSession.getCompanyDao().insert(company2);
        mDaoSession.getCompanyDao().insert(company3);

        Toast.makeText(this, "insert data finished....", Toast.LENGTH_SHORT).show();
    }

可以看到的结果为:

GreenDao3.2数据库使用教程_第6张图片

可以看到绑定的name是一致的。

第三种:
@ToMany
@JoinEntity(entity = A_AND_B.class,
sourceProperty = “referenceAId” ,
targetProperty = “referenceBId”)

个人感觉这个是最好理解的,同时感觉这个也是最greenDao中最接近多对多关系的一种模式。还是拿例子说话吧。一个城市图书馆很多书,那么图书馆与书就是一对多的关系,抽象成代码为:
Book.java:

@Entity
public class Book {
    @Id
    private Long _id;
    private String name ;
    private double price ;

    @Generated
    public Book(){}

City.java:[library不会写!!!]

@Entity
public class City {

    @Id
    private Long _id;

    private String name ;


    @ToMany
    @JoinEntity(entity = CityAndBooks.class,
                sourceProperty = "cityId" ,
                targetProperty = "bookId")
    private List bookList;

    @Generated
    public City(){}

中间体CityAndBooks.java:

@Entity
public class CityAndBooks {

    @Id
    private Long _id;
    private long bookId;
    private long cityId ;

    @Generated()
    public CityAndBooks() {
    }

编译之后,获取的表结构为:

GreenDao3.2数据库使用教程_第7张图片

图中可以看出,此时的一对多关系建立了三张表,而city_and_book表记录了city表的id,book表的id,相互查询时就是按照这张中间表进行的,我们插入数据看一下结果:

        City city = new City(null,"shanghai");
        City city1 = new City(null,"北京");

        Book book = new Book(null,"one night",40);
        Book book1 = new Book(null,"thinking in java",68);

        mDaoSession.getCityDao().insert(city);
        mDaoSession.getCityDao().insert(city1);

        mDaoSession.getBookDao().insert(book);
        mDaoSession.getBookDao().insert(book1);

        CityAndBooks cb = new CityAndBooks(null,book.get_id(),city.get_id());
        CityAndBooks cb1 = new CityAndBooks(null,book1.get_id() , city1.get_id());

        mDaoSession.getCityAndBooksDao().insert(cb);
        mDaoSession.getCityAndBooksDao().insert(cb1);

        Toast.makeText(this, "insert data finished....", Toast.LENGTH_SHORT).show();

我们来看一下结果:

GreenDao3.2数据库使用教程_第8张图片

可以看出,我们的city与book已经建立了联系,那么查询起来应该不是那么困难吧。

数据库的更新

对于greenDao,或者对于SQLite数据库更新,一般比较负责任的方式一般是这样的:
* 对于需要更新的表,创建临时表,复制数据
* 删除需要更新的表
* 创建新的目标表
* 将临时数据复制到新的目标表中,并删除临时表

这个就不说,下面的地址中会给出代码更新代码。

好了,greenDao的基本用法就介绍得差不多了,当然还有很多细节问题需要大家去注意了,这个只有大家在应用中去体会了,东西还是很多的,如果有问题或者疑惑,请留言。

所有代码地址为:https://github.com/Microhx/studyCodes/tree/master/testgreengao
效果图为:
GreenDao3.2数据库使用教程_第9张图片

你可能感兴趣的:(android进阶,android)