成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

GreenDao深入

longshengwang / 1924人閱讀

摘要:定義了一個(gè)這個(gè)標(biāo)記為源實(shí)體與另一個(gè)這個(gè)標(biāo)記為目標(biāo)實(shí)體的多個(gè)對(duì)象的關(guān)聯(lián)關(guān)系有一下三種方式來(lái)定義的映射關(guān)系。調(diào)試工具同時(shí)可以快速查看數(shù)據(jù)表結(jié)構(gòu)和數(shù)據(jù)。

大家好,在上一篇文章中,我主要介紹了GreenDao3.0的最基本的用法,當(dāng)然也是最常用的用法,如果你的項(xiàng)目里沒(méi)有特別復(fù)雜的多表關(guān)聯(lián)需求的話,我相信那篇文章的知識(shí)點(diǎn)已經(jīng)足夠使用了。但是,如果你是一個(gè)求知欲特別強(qiáng)的人或者手上有要在本地創(chuàng)建復(fù)雜的數(shù)據(jù)庫(kù)需求的話,我相信認(rèn)真讀完本篇文章,你一定會(huì)有所收獲。

好了廢話不多說(shuō),今天我們來(lái)學(xué)習(xí)下GreenDao的高級(jí)用法有哪些吧!閱讀本篇文章前你需要對(duì)GreenDao有一定的了解,如果你對(duì)GreenDao了解還不夠的話,建議先去閱讀史上最高效的ORM方案——GreenDao3.0詳解

目錄

session 緩存

多表關(guān)聯(lián)

多表查詢

自定義參數(shù)類(lèi)型

與數(shù)據(jù)庫(kù)操作相關(guān)的AS插件

session 緩存

如果你有多個(gè)相同的查詢語(yǔ)句去執(zhí)行,猜猜看返回給你的對(duì)象是一個(gè)還是多個(gè)?比如說(shuō)像下面這樣

QueryBuilder projectQueryBuilder = 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查詢出來(lái)的速度要比project1查詢出來(lái)的速度快很多倍;
這是因?yàn)樵谕粋€(gè)session中如果一個(gè)entities已經(jīng)被session記錄那么下一次再次操作該實(shí)體時(shí),greenDao會(huì)先從內(nèi)存中查找,如果內(nèi)存中沒(méi)有再去數(shù)據(jù)庫(kù)中查找。這樣一方面就極大的提高greenDao的查詢效率,另一方面也是需要特別注意的是當(dāng)entities更新過(guò) greenDao仍然會(huì)從內(nèi)存中取出舊值,所以如果entities更新過(guò),需要去調(diào)用daoseesion.clear()方法清除緩存后才能查到最新值,否則查詢到的將還是保存在內(nèi)存中的值。
下面介紹下清除緩存有兩種方法

清除所所有的緩存

daoSession.clear();

清除指定Dao類(lèi)的緩存

projectDao = daoSession.getNoteDao();
projectDao.detachAll();

多表關(guān)聯(lián)

1. 1:1關(guān)聯(lián)
當(dāng)我們?cè)谑褂胹qlite數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)表的1:1關(guān)聯(lián)時(shí),通常我們會(huì)在主表中定義一個(gè)外鍵去關(guān)聯(lián)副表,當(dāng)要查詢對(duì)應(yīng)的數(shù)據(jù)時(shí),首先我們要知道查詢數(shù)據(jù)的外鍵,然后需要用外鍵去副表中查詢所需要的數(shù)據(jù)。比如下面這樣

  public class Customer {
    private Long id;
  }
  public class Order {
    private Long id;
    private Date date;
    private long customerId;
  }

Customer表通過(guò)id與Order表關(guān)聯(lián),查詢Order的Customer時(shí)需要先知道Order中的customerId然后根據(jù)id=customerId值再去數(shù)據(jù)庫(kù)中查詢?cè)搃d所對(duì)應(yīng)的Customer對(duì)象。然而在greenDao中一個(gè)注釋就可以搞定,只需要使用@ToOne注釋來(lái)定義一個(gè)關(guān)聯(lián)對(duì)象即可。

@ToOne 定義了一個(gè)entities與另一個(gè)entities的1:1對(duì)應(yīng)關(guān)系。通過(guò)joinProperty參數(shù)來(lái)定義一個(gè)外鍵下面是代碼示例

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對(duì)象就能通過(guò)getCustomer()方法獲取Order所對(duì)應(yīng)的Customer了,這樣是不是很高效,很簡(jiǎn)便。其實(shí)getCustomer方法也很簡(jiǎn)單,就是在底層幫助我們封裝好了查詢語(yǔ)句而已,另外getCustomer獲取的對(duì)象也是懶查詢機(jī)制,只有真正使用getCustomer方法查詢到的對(duì)象時(shí)greenDao才會(huì)執(zhí)行查詢操作。如果你想立即執(zhí)行查詢操作可以調(diào)用DAO類(lèi)的loadDeep()與queryDeep()方法。

2. 1:N 關(guān)聯(lián)
在1對(duì)1關(guān)聯(lián)中每個(gè)顧客只能與一個(gè)訂單對(duì)應(yīng),但是現(xiàn)實(shí)生活中肯定不只是這樣,也會(huì)出現(xiàn)一個(gè)顧客下多個(gè)訂單的情況。如果出現(xiàn)這種需求的話,按照原生Sqlite的思路一樣是通過(guò)外鍵關(guān)聯(lián)即可,只是這一次查詢的對(duì)象會(huì)有很多個(gè),但是使用greenDao的1:1關(guān)聯(lián)方式顯然不行。不過(guò)別擔(dān)心greenDao還給我們準(zhǔn)備了@ToMany注釋。

@ToMany 定義了一個(gè)entities(這個(gè)標(biāo)記為源實(shí)體)與另一個(gè)entities(這個(gè)標(biāo)記為目標(biāo)實(shí)體)的多個(gè)對(duì)象的關(guān)聯(lián)關(guān)系:@Tomany有一下三種方式來(lái)定義1:N的映射關(guān)系。

referencedJoinProperty 在目標(biāo)實(shí)體中我們需要定義一個(gè)與源實(shí)體關(guān)聯(lián)起來(lái)的外鍵,即Order中的customerId,然后需要在源實(shí)體里我們需要將customerId作為referencedJoinProperty的屬性。說(shuō)起來(lái)很拗口,其實(shí)代碼很簡(jiǎn)單;

@Entity
public class Customer {
@Id private Long id;

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

@Entity
public class Order {
@Id private Long id;
private Date date;
private long customerId;
}

是不是很簡(jiǎn)單通過(guò)referencedJoinProperty來(lái)標(biāo)注下倆個(gè)實(shí)體之間的外鍵即可

joinProperties這個(gè)參數(shù)是referencedJoinProperty 參數(shù)的升級(jí)版。在referencedJoinProperty參數(shù)中我們發(fā)現(xiàn)倆個(gè)實(shí)體關(guān)聯(lián)的外鍵是CustomerId與id,但是如果我們的需求是外鍵不能通過(guò)id來(lái)定義,需要用自己自定義屬性來(lái)定義,第一種方法就沒(méi)法用了,而joinProperties就是為了解決這個(gè)需求的。

@Entity
public class Customer {
@Id private Long id;
@Unique private String tag;

@ToMany(joinProperties = {
        @JoinProperty(name = "tag", referencedName = "customerTag")
})
@OrderBy("date ASC")
private List orders;
}

@Entity
public class Order {
@Id private Long id;
private Date date;
@NotNull private String customerTag;
}

其實(shí)如果把
@ToMany(joinProperties = {
              @JoinProperty(name = "id", referencedName = "customerId")
      })
這樣的話就和第一種方法實(shí)現(xiàn)原理是一樣的了。

@JoinEntity 定義了N:M的映射關(guān)系。

@Entity
public class Product {
@Id private Long id;

@ToMany
@JoinEntity(
        entity = JoinProductsWithOrders.class,
        sourceProperty = "productId",
        targetProperty = "orderId"
)
private List ordersWithThisProduct;
}

@Entity
public class JoinProductsWithOrders {
@Id private Long id;
private Long productId;
private Long orderId;
}

@Entity
public class Order {
@Id private Long id;
}

3. 關(guān)聯(lián)表的更新與解析
關(guān)聯(lián)的查詢也是懶加載機(jī)制,而且查詢的結(jié)果會(huì)保存在緩存中下一次查詢的時(shí)候如果緩存有會(huì)直接從緩存中獲取結(jié)果。

同樣關(guān)聯(lián)表更新時(shí)因?yàn)橛芯彺鏅C(jī)制的存在你需要將改動(dòng)的表手動(dòng)的通過(guò)add()方法來(lái)更新關(guān)聯(lián)表中的對(duì)象或者直接清除緩存。

// 獲取當(dāng)前顧客的訂單列表
List orders1 = customer.getOrders();

// 插入一個(gè)新訂單
Order order = new Order();
order.setCustomerId(customer.getId());
daoSession.insert(order);

// 再一次獲取顧客的訂單
List orders2 = customer.getOrders();

// 因?yàn)榫彺媪斜頉](méi)有更新所以訂單1與訂單2的大小相等
assert(orders1.size() == orders2.size);
// 也是相同的對(duì)象
assert(orders1.equals(orders2));

//調(diào)用該方法后,才能更新緩存列表
orders1.add(newOrder);

//刪除時(shí)也許要手動(dòng)將緩存列表里面的數(shù)據(jù)刪除
List orders = customer.getOrders();
// 從數(shù)據(jù)庫(kù)中移除
daoSession.delete(someOrder);
// 手動(dòng)從緩存列表移除
orders.remove(someOrder);

//如果數(shù)據(jù)庫(kù)更新后不想手動(dòng)添加數(shù)據(jù)可以使用resetXX()方法來(lái)清除緩存

customer.resetOrders();
List orders = customer.getOrders();
多表查詢

有些時(shí)候我們的表沒(méi)有使用ToOneToMany建立關(guān)聯(lián)關(guān)系,但是我們又想一步到位。這時(shí)我們可以使用greenDao的多表查詢功能來(lái)幫助我們減少不必要的代碼。
1. 關(guān)聯(lián)單個(gè)表

//查詢地址是住在迪拜大樓的用戶
QueryBuilder queryBuilder = userDao.queryBuilder();
queryBuilder.join(Address.class, AddressDao.Properties.userId)
  .where(AddressDao.Properties.Street.eq("迪拜大樓"));
List users = queryBuilder.list();

通過(guò)queryBuilder.join()方法即可完成,其用法也很簡(jiǎn)單第一個(gè)參數(shù)是關(guān)聯(lián)的類(lèi),第二個(gè)是關(guān)聯(lián)類(lèi)中的關(guān)聯(lián)屬性。

2.關(guān)聯(lián)多個(gè)表

//查詢?cè)跉W洲人口超過(guò)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"));
List bigEuropeanCities = qb.list();

通過(guò)queryBuilder.join()鏈?zhǔn)秸{(diào)用來(lái)實(shí)現(xiàn)多表查詢
注意:多表查詢的前提是我們已經(jīng)定義好了外鍵來(lái)關(guān)聯(lián)表與表之間的關(guān)系。

自定義參數(shù)類(lèi)型

默認(rèn)類(lèi)型參數(shù) :greenDao默認(rèn)支持的類(lèi)型參數(shù)如下

boolean, Boolean
int, Integer
short, Short
long, Long
float, Float
double, Double
byte, Byte
byte[]
String
Date

自定義類(lèi)型參數(shù): 如果greenDao的默認(rèn)參數(shù)類(lèi)型滿足不了你的需求,比如你想定義一個(gè)顏色屬性,那么你可以使用數(shù)據(jù)庫(kù)支持的原生數(shù)據(jù)類(lèi)型通過(guò)PropertyConverter類(lèi)轉(zhuǎn)換成你想要的顏色屬性。

首先你需要給自定義類(lèi)型參數(shù)添加 @Convert注釋并添加對(duì)應(yīng)參數(shù)
converter:參數(shù)轉(zhuǎn)換類(lèi),columnType:在數(shù)據(jù)庫(kù)中對(duì)應(yīng)的類(lèi)型

實(shí)現(xiàn)PropertyConverter類(lèi)
下面是用通過(guò)使用數(shù)據(jù)庫(kù)支持的Integer類(lèi)型來(lái)轉(zhuǎn)換成數(shù)據(jù)庫(kù)不支持的枚舉類(lèi)型

@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 {
//將Integer值轉(zhuǎn)換成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值轉(zhuǎn)換成Integer值
  @Override
  public Integer convertToDatabaseValue(Role entityProperty) {
      return entityProperty == null ? null : entityProperty.id;
  }
}
}

與數(shù)據(jù)庫(kù)相關(guān)的AS插件

快速清除數(shù)據(jù)庫(kù)本地?cái)?shù)據(jù)。ADB IDEA

調(diào)試工具同時(shí)可以快速查看數(shù)據(jù)表結(jié)構(gòu)和數(shù)據(jù)。 Stetho

感興趣的同學(xué)可以搜索下這倆個(gè)插件真的很好用。

后記

上期有同學(xué)提問(wèn)greenDao的多線程同步機(jī)制,在這里我簡(jiǎn)單解釋下:
greenDao多線程同步可以通過(guò)forCurrentThread()來(lái)實(shí)現(xiàn)的,具體原理很簡(jiǎn)單我們看下源碼就知道了

      //獲取當(dāng)前線程id
       long threadId = Thread.currentThread().getId();
      //加鎖
        synchronized (queriesForThreads) {
            //queryRef是一個(gè)Map集合
            WeakReference queryRef = 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是通過(guò)將線程id與query對(duì)象存儲(chǔ)在Map集合中建立1:N的映射關(guān)系,不同線程只會(huì)取出屬于自己的query而不會(huì)調(diào)用其他線程的query。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70577.html

相關(guān)文章

  • GreenDao入門(mén)

    摘要:核心類(lèi)介紹是的入口也是頂級(jí)對(duì)象對(duì)于一個(gè)指定的表單持有數(shù)據(jù)庫(kù)對(duì)象數(shù)據(jù)庫(kù)并且能夠管理類(lèi)能夠創(chuàng)建表和刪除表其內(nèi)部類(lèi)與是創(chuàng)建數(shù)據(jù)庫(kù)的的具體實(shí)現(xiàn)對(duì)于一個(gè)指定的表單可以管理所有的對(duì)象。也能夠?qū)?shí)體類(lèi)執(zhí)行,操作。 1. 什么是greenDao 弄明白greenDao之前我們應(yīng)該先了解什么是ORM(Object Relation Mapping 即 對(duì)象關(guān)系映射),說(shuō)白了就是將面向?qū)ο缶幊陶Z(yǔ)言里的對(duì)象...

    edagarli 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<