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
效果圖為: