Android ORM 框架:GreenDao 使用詳解(進階篇)

Speedy發表於2017-07-03

本文作者:speedy
CSDN 專欄:blog.csdn.net/speedystone…
掘金專欄:juejin.im/post/595a12…

前言

Android ORM 框架:GreenDao 使用詳解(基礎篇 中,我們瞭解了 GreenDao 的基本使用,本文我們將深入講解 GreenDao 的使用 。

一、複雜表結構

a, 使用 @ToOne 建立一對一 ( 1 : 1) 關係

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

    private long customerId;

    @ToOne(joinProperty = "customerId")
    private Customer customer;
}

@Entity
public class Customer {
    @Id 
    private Long id;
}複製程式碼

b,使用 @ToMany 建立一對多 (1: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;
}複製程式碼

c, 使用@JoinEntity 建立多對多(N : M)關係

@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;
}複製程式碼

二、自定義型別

1,GreenDao 預設支援的型別有

boolean, Boolean
int, Integer
short, Short
long, Long
float, Float
double, Double
byte, Byte
byte[]
String
Date複製程式碼

2,通過 @Convert 註解轉換資料型別

例如:將列舉型別轉換成整形

@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 {
        @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;
        }

        @Override
        public Integer convertToDatabaseValue(Role entityProperty) {
            return entityProperty == null ? null : entityProperty.id;
        }
    }複製程式碼

三、複雜查詢

a, 條件查詢

方法一:

List joes = userDao.queryRaw("where AGE>?","10");//查詢年齡大於10的使用者複製程式碼

方法二:

List joes = userDao.queryBuilder().where(UserDao.Properties.Age.gt("10")).list();複製程式碼

b, 排序

// order by last name
queryBuilder.orderAsc(Properties.LastName);

// in reverse
queryBuilder.orderDesc(Properties.LastName);

// order by last name and year of birth
queryBuilder.orderAsc(Properties.LastName).orderDesc(Properties.YearOfBirth);複製程式碼

c, 分頁

limit(int) : 限制查詢返回的結果的數量。
offset(int): 設定起始位置

// 從第二條記錄開始查詢5條記錄
List list = userDao.queryBuilder()
                .offset(2)
                .limit(5)
                .list();複製程式碼

d, 懶載入

LazyList lazyList = userDao.queryBuilder().listLazy();

for (User u:lazyList) {
      Log.i(TAG, "使用者名稱:"+u.getName());
}

lazyList.close();   //不再使用時必須關閉,否則會導致資料庫遊標未關閉,從而導致記憶體洩漏複製程式碼

LazyList 是 GreenDao 實現的集合類,實現了 List 介面,所以,直接把 LazyList 當做List 來使用即可,

public class LazyList implements List, Closeable {
//省略了具體實現
}複製程式碼

注意: LazyList 不再使用時必須呼叫用 close() 方法關閉,否則會導致記憶體洩漏 。

lazyList.close();複製程式碼

e, 故障查詢

很多時候我們在查詢的時候不能查詢到我們期望的結果,這個時候我們可以通過修改 QueryBuilder 的兩個靜態成員變數來列印 SQL 日誌,便於排查問題。

QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;複製程式碼

f, 多表聯合查詢

QueryBuilder queryBuilder = userDao.queryBuilder();

queryBuilder.join(Address.class, AddressDao.Properties.userId)
  .where(AddressDao.Properties.Street.eq("Sesame Street"));

List users = queryBuilder.list();複製程式碼

四、混淆配置

### greenDAO 3
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties

# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
# If you do not use RxJava:
-dontwarn rx.**

### greenDAO 2
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties複製程式碼

五、資料庫加密

greenDAO 支援 SQLCipher 直接繫結。

a, 引入依賴:

compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'複製程式碼

b, 初始化加密資料庫

DevOpenHelper helper = new DevOpenHelper(this, "notes-db-encrypted.db");
Database db = helper.getEncryptedWritableDb("");
daoSession = new DaoMaster(db).newSession();複製程式碼

c、其他操作和未加密一樣(是不是特別簡單)

當然,如果你不是使用 GreenDao 資料庫,同樣可以使用 SQLCipher 加密保護我們的資料,詳細請參考 SQLCipher for Android

六,整合 RxJava

Rxjava 的火爆程度已經是如日中天了,GreenDao 對當然也是對提供對 Rxjava 的支援。(比較失望的是目前 GreedDao 僅支援 Rxjava 1,不支援 Rxjava 2)

1,引入 Rxjava 依賴

compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.9'複製程式碼

3,初始化 GreedDao 配置

public class App extends Application {
    /**
     * 加密識別符號
     */
    public static final boolean ENCRYPTED = true;

    private DaoSession daoSession;

    @Override
    public void onCreate() {
        super.onCreate();

        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,ENCRYPTED ? "notes-db-encrypted" : "notes-db");
        Database db = ENCRYPTED ? helper.getEncryptedWritableDb("super-secret") : helper.getWritableDb();
        daoSession = new DaoMaster(db).newSession();
    }

    public DaoSession getDaoSession() {
        return daoSession;
    }
}複製程式碼

3, 獲取 RxDao

 User user = new User();
 user.setUserId(10);
 user.setName("小紅");
 user.setAge(18);

 DaoSession daoSession = ((MyApp) getApplication()).getDaoSession();
 RxDao userDao = daoSession.getUserDao().rx();

 userDao.insert(user)
         .observeOn(AndroidSchedulers.mainThread())
         .subscribe(new Action1() {
             @Override
             public void call(User user) {
                 Log.i(TAG, "儲存成功 ");
             }
         });複製程式碼

相關文章