1. 程式人生 > >GreenDao3.2資料庫使用教程

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,如下圖(其他檔案無視即可):
這裡寫圖片描述

同時再回過頭來,你會發現你的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>);  //批量插入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<Long> idList);       //刪除id為idList中的User
userDao.deleteInTx(List<User> userList);          //刪除集合中的user
userDao.delete(user);                             //刪除目標User[需要包含主鍵]

還可以使用條件刪除,使用StringCondition模式,刪除name=micro和age>20歲的人

QueryBuilder<User> 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<User> 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>);    //批量修改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<User> queryBuilder = mDaoSession.queryBuilder(User.class);

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

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

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

通過PropertyCondition查詢

QueryBuilder<User> 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<User> 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表的結構為:

這裡寫圖片描述

我們看到了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<Order> orders;

    @Generated()
    public Customer() {
    }

在Custom中使用註解@ToMany, 其referencedJoinProperty 對應Order物件中的customerId 對應的多個訂單為List型別,生成的表的結構為:

這裡寫圖片描述

插入資料:

    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();
    }

這裡寫圖片描述

第二種:
@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<Company> 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(){}
}

編譯成功之後,我們檢視兩張表的結構:

這裡寫圖片描述

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();
    }

可以看到的結果為:

這裡寫圖片描述

可以看到繫結的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<Book> bookList;

    @Generated
    public City(){}

中間體CityAndBooks.java:

@Entity
public class CityAndBooks {

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

    @Generated()
    public CityAndBooks() {
    }

編譯之後,獲取的表結構為:

這裡寫圖片描述

圖中可以看出,此時的一對多關係建立了三張表,而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();

我們來看一下結果:

這裡寫圖片描述

可以看出,我們的city與book已經建立了聯絡,那麼查詢起來應該不是那麼困難吧。

資料庫的更新

對於greenDao,或者對於SQLite資料庫更新,一般比較負責任的方式一般是這樣的:
* 對於需要更新的表,建立臨時表,複製資料
* 刪除需要更新的表
* 建立新的目標表
* 將臨時資料複製到新的目標表中,並刪除臨時表

這個就不說,下面的地址中會給出程式碼更新程式碼。

好了,greenDao的基本用法就介紹得差不多了,當然還有很多細節問題需要大家去注意了,這個只有大家在應用中去體會了,東西還是很多的,如果有問題或者疑惑,請留言。

所有程式碼地址為:https://github.com/Microhx/studyCodes/tree/master/testgreengao
效果圖為:
這裡寫圖片描述