這一篇將帶給大家greenDao的一些比較高級的用法。
以下內容參考[官網](http://greendao-orm.com/)
關系型數據庫,當然少不了多表關聯,SQLite也不例外。那么我們就下來看下greenDao如何建立表關聯
- 一對一 1:1 entity.addToOne(entity,property)
我們以人和身份證為例,
~~~
/**
* 人實體
*/
Entity people = schema.addEntity("People");
people.addStringProperty("name").primaryKey(); //名字
people.addIntProperty("age"); //年齡
/**
* 身份證
*/
Entity idcard = schema.addEntity("IdCard");
idcard.addStringProperty("idcardnum").primaryKey(); //身份證號
/**
* 人和身份證 是一對一的關系
*/
/** 一個人對應一個idcard **/
Property propertyidcardnum = people.addStringProperty("idcardnum").getProperty();
people.addToOne(idcard, propertyidcardnum);
/** 一個idcrad 對應一個name ***/
Property propertyname = idcard.addStringProperty("name").getProperty();
idcard.addToOne(people, propertyname);
~~~
注意:當我們要建立多表關聯的時候,就不在添加id主鍵了,以為我們這里的主鍵要當成其他表的外鍵使用。
上面我們通過entity.addToOne(otherEntity,peoperty)來建立一對一關聯,關系為,entity和otherentity通過peroperty來建立關聯,其中peoperty在otherentity中式主鍵,在entity中是外鍵。這么干說,誰也記不住。看代碼
~~~
Property propertyidcardnum = people.addStringProperty("idcardnum").getProperty();
people.addToOne(idcard, propertyidcardnum);
~~~
我們將身份證實體中的主鍵idcardnum,當成外鍵以一對一的關系添加到people實體中了,就是這么簡單。
- 一對多 1:n addToMany(entity,property)
~~~
Entity order = schema.addEntity("Order");
order.addIntProperty("orderid").primaryKey();
order.addDoubleProperty("money").notNull();
/**
* 建立人與訂單的一對多關系
*/
// Property propertypeoplenum=people.addStringProperty("idcardnum").getProperty();
Property property = order.addStringProperty("name").getProperty();
order.addToOne(people, property);
people.addToMany(order,propertyname).setName("orders");
~~~
我在這里建立了一個購物的實體。形成一對多關系 。并將訂單中的主鍵id,以多對一的形式給people當外鍵。
- 多對多 m:n
~~~
Entity course = schema.addEntity("Course");
course.addStringProperty("courseid").primaryKey();
course.addStringProperty("coursename").notNull();
Property propertyPeopleId = course.addStringProperty("name").getProperty();
course.addToMany(people,propertyPeopleId);
Property propertyCourseID = people.addStringProperty("courseid").getProperty();
people.addToMany(course,propertyCourseID);
~~~
,這個就和上面的一樣了,我就不再多少了。
需要注意的是,這里的關系特別繞,一不小心就會弄錯。
現在,我們去看看生成的實體類有什么區別。
先看People,我們還記得,和身份證是一對一,和訂單是一對多,和課程是多對多。
~~~
private String name;
private Integer age;
private String idcardnum;
private String courseid;
/** Used to resolve relations */
private transient DaoSession daoSession;
/** Used for active entity operations. */
private transient PeopleDao myDao;
private IdCard idCard;
private String idCard__resolvedKey;
private List<Order> orders;
private List<Course> courseList;
~~~
看到沒,成員變量這里有了IdCard(單一),List< Order> ,List< Course >,確實是形成了上面我們寫的關系。
接下來我們看下構造函數
~~~
public People(String name, Integer age, String idcardnum, String courseid) {
this.name = name;
this.age = age;
this.idcardnum = idcardnum;
this.courseid = courseid;
}
~~~
構造函數里面只是幾個相關表的主鍵。。沒什么奇怪的。那么我們看下,這個類下面都有什么方法。

有發現,我們會發現這里面有getCourseList 和 getOrderList,我們挑一個來看看
~~~
public List<Order> getOrders() {
if (orders == null) {
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
OrderDao targetDao = daoSession.getOrderDao();
List<Order> ordersNew = targetDao._queryPeople_Orders(name);
synchronized (this) {
if(orders == null) {
orders = ordersNew;
}
}
}
return orders;
}
~~~
看到,這里通過name來查詢,為什么呢?因為我們這個name是Order表的外鍵。哈哈,這樣就爽了,都直接給提供方法了,都不同我們自己搞。恩,確實爽。
我們再看看_queryPeople_Orders()方法
~~~
public List<Order> _queryPeople_Orders(String name) {
synchronized (this) {
if (people_OrdersQuery == null) {
QueryBuilder<Order> queryBuilder = queryBuilder();
queryBuilder.where(Properties.Name.eq(null));
people_OrdersQuery = queryBuilder.build();
}
}
Query<Order> query = people_OrdersQuery.forCurrentThread();
query.setParameter(0, name);
return query.list();
}
~~~
不粗,果然是給我們封裝好了的。啥,這種查詢方法,看不懂?沒事,我們后面會介紹到。
多表關聯我們看完了,這里你要注意一個坑,那就是 關聯的2張表的主鍵類型一定要一樣,別問我為什么。
- 其他用法
添加約束 無非就是添加 主鍵 非空 自增等等。

如:
~~~
order.addIntProperty("orderid").primaryKey();
~~~
多線程下
~~~
Query<Order> query = people_OrdersQuery.forCurrentThread();
~~~
多條件查詢
~~~
名字叫“喬”和(出生年份大于1970或(出生年份是1970年,出生月等于或大于10(10月)。
* QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List youngJoes = qb.list();
~~~
或者
~~~
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
.build();
List joesOf1970 = query.list();
~~~
或者
~~~
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
~~~
嵌套查詢
~~~
Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();
~~~
鏈接查詢
~~~
使用連接查詢 查詢用戶名為admin
Query query = userDao.queryRawCreate(
", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
~~~
我們再來看看query的幾個list…方法
> list() 所有的實體都被加載到內存中,結果是一個ArrayList,比較容易使用
listLazy() 實體按照需求加載,并不會查詢完立即加載進內存,只會在需要的時候加載,并且會緩存在一個list之中,并需調用close關閉
listLazyUnCached() 一個虛擬的實體集,任何訪問都必須從數據庫中加載,必須被關閉
listIterator() 讓你便利加載,數據沒有被緩存,必須關閉
代碼混淆
~~~
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
~~~
或者去github上看他們demo如何混淆的。
- 數據庫升級
本以為這么好個東西數據庫升級的一些問題肯定也弄好了,哎,結果。多說無益,我們來看看他封裝的代碼把。
~~~
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,"persons-db",null);
~~~
~~~
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
~~~
~~~
public static void dropAllTables(SQLiteDatabase db, boolean ifExists) {
PersonDao.dropTable(db, ifExists);
PeopleDao.dropTable(db, ifExists);
IdCardDao.dropTable(db, ifExists);
OrderDao.dropTable(db, ifExists);
CourseDao.dropTable(db, ifExists);
}
~~~
~~~
public static void dropTable(SQLiteDatabase db, boolean ifExists) {
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"PERSON\"";
db.execSQL(sql);
}
~~~
看見沒,根本沒有所謂的數據庫升級,還把原來的數據庫給刪除了。擦。那怎么辦呢。別著急,雖然咱垃圾,但是思路還是有的,
怎么辦呢?
第一步,我們在生成生成實體類的文件中。
~~~
schema.enableKeepSectionsByDefault();//通過次Schema對象添加的所有實體都不會覆蓋自定義的代碼 或者根據需要添加其他()
~~~
這樣我們再生成的時候就不會覆蓋了。
第二步,咱給出一個連接,你們看吧。(本屌太渣)
[greenDao數據庫升級](http://blog.csdn.net/fancylovejava/article/details/46713445)
到此為止:
參考資料:[greenDao官網](http://greendao-orm.com/)
- 前言
- Android四大圖片緩存框架之-Fresco(一)
- Android四大圖片緩存框架之-Fresco之initialize(二)
- Android 四大緩存框架之-Universal-Image-Loader
- Android四大圖片緩存框架之-Picasso和Glide
- Android ORM數據庫框架之-greenDao(一)
- Android ORM數據庫框架之-greenDao(二)
- Android ORM數據庫框架之-greenDao(三)
- Android ORM數據庫框架之-greenDao(四)
- Android 網絡開源庫之-retrofit
- RxJava的簡單學習(學習自扔物線)
- Android ORM框架之-ActiveAndroid的簡單分析