Android ORM 框架:GreenDao 使用详解(进阶篇)

前言

在 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

b,使用 @ToMany 建立一对多 (1:N ) 关系

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

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

@Entity
public class Order {
    @Id private Long id;
    private Date date;
    private long customerId;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

c, 使用@JoinEntity 建立多对多(N : M)关系

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

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

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

@Entity
public class Order {
    @Id private Long id;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

二、自定义类型

1,GreenDao 默认支持的类型有

boolean, Boolean
int, Integer
short, Short
long, Long
float, Float
double, Double
byte, Byte
byte[]
String
Date
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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<Role, Integer> {
        @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;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

三、复杂查询

a, 条件查询

方法一:

List<User> joes = userDao.queryRaw("where AGE>?","10");//查询年龄大于10的用户
  • 1

方法二:

List<User> joes = userDao.queryBuilder().where(UserDao.Properties.Age.gt("10")).list();
  • 1

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

c, 分页

limit(int) : 限制查询返回的结果的数量。 
offset(int): 设置起始位置

// 从第二条记录开始查询5条记录
List<User> list = userDao.queryBuilder()
                .offset(2)
                .limit(5)
                .list();
  • 1
  • 2
  • 3
  • 4
  • 5

d, 懒加载

LazyList<User> lazyList = userDao.queryBuilder().listLazy();

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

lazyList.close();   //不再使用时必须关闭,否则会导致数据库游标未关闭,从而导致内存泄漏
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

LazyList 是 GreenDao 实现的集合类,实现了 List 接口,所以,直接把 LazyList 当做List 来使用即可,

public class LazyList<E> implements List<E>, Closeable {
//省略了具体实现
}
  • 1
  • 2
  • 3

注意: LazyList 不再使用时必须调用用 close() 方法关闭,否则会导致内存泄漏 。

lazyList.close();
  • 1

e, 故障查询

很多时候我们在查询的时候不能查询到我们期望的结果,这个时候我们可以通过修改 QueryBuilder 的两个静态成员变量来打印 SQL 日志,便于排查问题。

QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
  • 1
  • 2

f, 多表联合查询

QueryBuilder<User> queryBuilder = userDao.queryBuilder();

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

List<User> users = queryBuilder.list();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

四、混淆配置

### 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

五、数据库加密

greenDAO 支持 SQLCipher 直接绑定。

a, 引入依赖:

compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'
  • 1

b, 初始化加密数据库

DevOpenHelper helper = new DevOpenHelper(this, "notes-db-encrypted.db");
Database db = helper.getEncryptedWritableDb("<your-secret-password>");
daoSession = new DaoMaster(db).newSession();
  • 1
  • 2
  • 3

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'
  • 1
  • 2

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

3, 获取 RxDao

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

 DaoSession daoSession = ((MyApp) getApplication()).getDaoSession();
 RxDao<User, Long> userDao = daoSession.getUserDao().rx();

 userDao.insert(user)
         .observeOn(AndroidSchedulers.mainThread())
         .subscribe(new Action1<User>() {
             @Override
             public void call(User user) {
                 Log.i(TAG, "保存成功 ");
             }
         });

猜你喜欢

转载自blog.csdn.net/chenli_001/article/details/79591322