摘要:定義了一個這個標記為源實體與另一個這個標記為目標實體的多個對象的關聯關系有一下三種方式來定義的映射關系。調試工具同時可以快速查看數據表結構和數據。
大家好,在上一篇文章中,我主要介紹了GreenDao3.0的最基本的用法,當然也是最常用的用法,如果你的項目里沒有特別復雜的多表關聯需求的話,我相信那篇文章的知識點已經足夠使用了。但是,如果你是一個求知欲特別強的人或者手上有要在本地創建復雜的數據庫需求的話,我相信認真讀完本篇文章,你一定會有所收獲。
好了廢話不多說,今天我們來學習下GreenDao的高級用法有哪些吧!閱讀本篇文章前你需要對GreenDao有一定的了解,如果你對GreenDao了解還不夠的話,建議先去閱讀史上最高效的ORM方案——GreenDao3.0詳解
目錄session 緩存
多表關聯
多表查詢
自定義參數類型
與數據庫操作相關的AS插件
session 緩存如果你有多個相同的查詢語句去執行,猜猜看返回給你的對象是一個還是多個?比如說像下面這樣
QueryBuilderprojectQueryBuilder = projectDao .queryBuilder() .where(ProjectDao.Properties.UserName.eq("123456")); Query query = projectQueryBuilder.build(); Project project1=query.unique(); QueryBuilder projectQueryBuilder1 = projectDao .queryBuilder() .where(ProjectDao.Properties.UserName.eq("123456")); Query query2 = projectQueryBuilder1.build(); Project project2=query.unique();
答案是project1==project2而且project2查詢出來的速度要比project1查詢出來的速度快很多倍;
這是因為在同一個session中如果一個entities已經被session記錄那么下一次再次操作該實體時,greenDao會先從內存中查找,如果內存中沒有再去數據庫中查找。這樣一方面就極大的提高greenDao的查詢效率,另一方面也是需要特別注意的是當entities更新過 greenDao仍然會從內存中取出舊值,所以如果entities更新過,需要去調用daoseesion.clear()方法清除緩存后才能查到最新值,否則查詢到的將還是保存在內存中的值。
下面介紹下清除緩存有兩種方法
清除所所有的緩存
daoSession.clear();
清除指定Dao類的緩存
projectDao = daoSession.getNoteDao(); projectDao.detachAll();多表關聯
1. 1:1關聯
當我們在使用sqlite數據庫來實現表的1:1關聯時,通常我們會在主表中定義一個外鍵去關聯副表,當要查詢對應的數據時,首先我們要知道查詢數據的外鍵,然后需要用外鍵去副表中查詢所需要的數據。比如下面這樣
public class Customer { private Long id; } public class Order { private Long id; private Date date; private long customerId; }
Customer表通過id與Order表關聯,查詢Order的Customer時需要先知道Order中的customerId然后根據id=customerId值再去數據庫中查詢該id所對應的Customer對象。然而在greenDao中一個注釋就可以搞定,只需要使用@ToOne注釋來定義一個關聯對象即可。
@ToOne 定義了一個entities與另一個entities的1:1對應關系。通過joinProperty參數來定義一個外鍵下面是代碼示例
public class Order { @Id private Long id; private long customerId; @ToOne(joinProperty = "customerId") private Customer customer; } @Entity public class Customer { @Id private Long id; }
這樣只要獲得Order對象就能通過getCustomer()方法獲取Order所對應的Customer了,這樣是不是很高效,很簡便。其實getCustomer方法也很簡單,就是在底層幫助我們封裝好了查詢語句而已,另外getCustomer獲取的對象也是懶查詢機制,只有真正使用getCustomer方法查詢到的對象時greenDao才會執行查詢操作。如果你想立即執行查詢操作可以調用DAO類的loadDeep()與queryDeep()方法。
2. 1:N 關聯
在1對1關聯中每個顧客只能與一個訂單對應,但是現實生活中肯定不只是這樣,也會出現一個顧客下多個訂單的情況。如果出現這種需求的話,按照原生Sqlite的思路一樣是通過外鍵關聯即可,只是這一次查詢的對象會有很多個,但是使用greenDao的1:1關聯方式顯然不行。不過別擔心greenDao還給我們準備了@ToMany注釋。
@ToMany 定義了一個entities(這個標記為源實體)與另一個entities(這個標記為目標實體)的多個對象的關聯關系:@Tomany有一下三種方式來定義1:N的映射關系。
referencedJoinProperty 在目標實體中我們需要定義一個與源實體關聯起來的外鍵,即Order中的customerId,然后需要在源實體里我們需要將customerId作為referencedJoinProperty的屬性。說起來很拗口,其實代碼很簡單;
@Entity public class Customer { @Id private Long id; @ToMany(referencedJoinProperty = "customerId") @OrderBy("date ASC") private Listorders; } @Entity public class Order { @Id private Long id; private Date date; private long customerId; }
是不是很簡單通過referencedJoinProperty來標注下倆個實體之間的外鍵即可
joinProperties這個參數是referencedJoinProperty 參數的升級版。在referencedJoinProperty參數中我們發現倆個實體關聯的外鍵是CustomerId與id,但是如果我們的需求是外鍵不能通過id來定義,需要用自己自定義屬性來定義,第一種方法就沒法用了,而joinProperties就是為了解決這個需求的。
@Entity public class Customer { @Id private Long id; @Unique private String tag; @ToMany(joinProperties = { @JoinProperty(name = "tag", referencedName = "customerTag") }) @OrderBy("date ASC") private Listorders; } @Entity public class Order { @Id private Long id; private Date date; @NotNull private String customerTag; }
其實如果把
@ToMany(joinProperties = { @JoinProperty(name = "id", referencedName = "customerId") })
這樣的話就和第一種方法實現原理是一樣的了。
@JoinEntity 定義了N:M的映射關系。
@Entity public class Product { @Id private Long id; @ToMany @JoinEntity( entity = JoinProductsWithOrders.class, sourceProperty = "productId", targetProperty = "orderId" ) private ListordersWithThisProduct; } @Entity public class JoinProductsWithOrders { @Id private Long id; private Long productId; private Long orderId; } @Entity public class Order { @Id private Long id; }
3. 關聯表的更新與解析
關聯的查詢也是懶加載機制,而且查詢的結果會保存在緩存中下一次查詢的時候如果緩存有會直接從緩存中獲取結果。
同樣關聯表更新時因為有緩存機制的存在你需要將改動的表手動的通過add()方法來更新關聯表中的對象或者直接清除緩存。
// 獲取當前顧客的訂單列表 List多表查詢orders1 = customer.getOrders(); // 插入一個新訂單 Order order = new Order(); order.setCustomerId(customer.getId()); daoSession.insert(order); // 再一次獲取顧客的訂單 List orders2 = customer.getOrders(); // 因為緩存列表沒有更新所以訂單1與訂單2的大小相等 assert(orders1.size() == orders2.size); // 也是相同的對象 assert(orders1.equals(orders2)); //調用該方法后,才能更新緩存列表 orders1.add(newOrder); //刪除時也許要手動將緩存列表里面的數據刪除 List orders = customer.getOrders(); // 從數據庫中移除 daoSession.delete(someOrder); // 手動從緩存列表移除 orders.remove(someOrder); //如果數據庫更新后不想手動添加數據可以使用resetXX()方法來清除緩存 customer.resetOrders(); List orders = customer.getOrders();
有些時候我們的表沒有使用ToOne與ToMany建立關聯關系,但是我們又想一步到位。這時我們可以使用greenDao的多表查詢功能來幫助我們減少不必要的代碼。
1. 關聯單個表
//查詢地址是住在迪拜大樓的用戶 QueryBuilderqueryBuilder = userDao.queryBuilder(); queryBuilder.join(Address.class, AddressDao.Properties.userId) .where(AddressDao.Properties.Street.eq("迪拜大樓")); List users = queryBuilder.list();
通過queryBuilder.join()方法即可完成,其用法也很簡單第一個參數是關聯的類,第二個是關聯類中的關聯屬性。
2.關聯多個表
//查詢在歐洲人口超過100000的城市 QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000)); Join country = qb.join(Properties.CountryId, Country.class); Join continent = qb.join(country, CountryDao.Properties.ContinentId, Continent.class, ContinentDao.Properties.Id); continent.where(ContinentDao.Properties.Name.eq("Europe")); ListbigEuropeanCities = qb.list();
通過queryBuilder.join()鏈式調用來實現多表查詢
注意:多表查詢的前提是我們已經定義好了外鍵來關聯表與表之間的關系。
默認類型參數 :greenDao默認支持的類型參數如下
boolean, Boolean int, Integer short, Short long, Long float, Float double, Double byte, Byte byte[] String Date
自定義類型參數: 如果greenDao的默認參數類型滿足不了你的需求,比如你想定義一個顏色屬性,那么你可以使用數據庫支持的原生數據類型通過PropertyConverter類轉換成你想要的顏色屬性。
首先你需要給自定義類型參數添加 @Convert注釋并添加對應參數
converter:參數轉換類,columnType:在數據庫中對應的類型
實現PropertyConverter類
下面是用通過使用數據庫支持的Integer類型來轉換成數據庫不支持的枚舉類型
@Entity public class User { @Id private Long id; @Convert(converter = RoleConverter.class, columnType = Integer.class) private Role role; public enum Role { DEFAULT(0), AUTHOR(1), ADMIN(2); final int id; Role(int id) { this.id = id; } } public static class RoleConverter implements PropertyConverter與數據庫相關的AS插件{ //將Integer值轉換成Role值 @Override public Role convertToEntityProperty(Integer databaseValue) { if (databaseValue == null) { return null; } for (Role role : Role.values()) { if (role.id == databaseValue) { return role; } } return Role.DEFAULT; } //將Role值轉換成Integer值 @Override public Integer convertToDatabaseValue(Role entityProperty) { return entityProperty == null ? null : entityProperty.id; } } }
快速清除數據庫本地數據。ADB IDEA
調試工具同時可以快速查看數據表結構和數據。 Stetho
感興趣的同學可以搜索下這倆個插件真的很好用。
后記上期有同學提問greenDao的多線程同步機制,在這里我簡單解釋下:
greenDao多線程同步可以通過forCurrentThread()來實現的,具體原理很簡單我們看下源碼就知道了
//獲取當前線程id long threadId = Thread.currentThread().getId(); //加鎖 synchronized (queriesForThreads) { //queryRef是一個Map集合 WeakReferencequeryRef = queriesForThreads.get(threadId); Q query = queryRef != null ? queryRef.get() : null; if (query == null) { gc(); query = createQuery(); //保存query queriesForThreads.put(threadId, new WeakReference(query)); } else { System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length); } return query; }
這是源碼的核心部分,從上面我們可以看出greenDao是通過將線程id與query對象存儲在Map集合中建立1:N的映射關系,不同線程只會取出屬于自己的query而不會調用其他線程的query。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70577.html
摘要:核心類介紹是的入口也是頂級對象對于一個指定的表單持有數據庫對象數據庫并且能夠管理類能夠創建表和刪除表其內部類與是創建數據庫的的具體實現對于一個指定的表單可以管理所有的對象。也能夠對實體類執行,操作。 1. 什么是greenDao 弄明白greenDao之前我們應該先了解什么是ORM(Object Relation Mapping 即 對象關系映射),說白了就是將面向對象編程語言里的對象...
閱讀 2566·2021-11-22 09:34
閱讀 3547·2021-11-15 11:37
閱讀 2346·2021-09-13 10:37
閱讀 2108·2021-09-04 16:40
閱讀 1577·2021-09-02 15:40
閱讀 2461·2019-08-30 13:14
閱讀 3332·2019-08-29 13:42
閱讀 1907·2019-08-29 13:02