Android ORM 框架之 greenDAO应用基础

greenDAO是时下Android最流行的一款ORM框架,其性能高,可加密,使用简洁,做android开发,如果会使用它,工作量会大大减小。其性能与其他ORM框架之比较可以查阅其官网。
目前greenDAO版本为3.1.1,greenDAO3相较于greenDAO2发生了较大的改变:可以使用注解声明schemas和实体。有两种方式使用greenDAO3,一种是使用java库的形式(greenDAO2的使用方法),一种是基于注解的形式(greenDAO3新增的)。

方式一,java库形式

1>在 src/main 目录下新建一个与 java 同层级的java-gen目录,用于存放由 greendao生成的 Bean类、DAO类、DaoMaster、DaoSession 等类:
Android ORM 框架之 greenDAO应用基础_第1张图片
2> 在build.gradle(app),添加 sourceSets 与依赖:

sourceSets {
        main {
            java.srcDirs = ['src/main/java', 'src/main/java-gen']
        }
    }
dependencies {
    compile 'org.greenrobot:greendao:3.1.0'
    // This is only needed if you want to use encrypted databases
    compile 'net.zetetic:android-database-sqlcipher:3.5.1'
}

3>新建java库模块:File -> New -> New Module -> Java Library
Android ORM 框架之 greenDAO应用基础_第2张图片
Android ORM 框架之 greenDAO应用基础_第3张图片
4>在java库模块build.gradledependencies中添加依赖:

dependencies {
    compile 'org.greenrobot:greendao-generator:3.1.0'
}

5>编写java库模块生成的类,创建实体(表):

public class Generator {
    public static void  main(String[] args) throws Exception {
        int version = 1;
        String defaultPackage = "com.example.bean";
        //创建模式对象,指定版本号和自动生成的bean对象的包名
        Schema schema = new Schema(version, defaultPackage);
        //指定自动生成的dao对象的包名,不指定则都DAO类生成在"com.example.bean"包中
        schema.setDefaultJavaPackageDao("com.example.dao");

        //添加实体
        addEntity(schema);
        //java-gen绝对路径
        String outDir = "H:/Persion/app/src/main/java-gen";
        //调用DaoGenerator().generateAll方法自动生成代码到之前创建的java-gen目录下
        new DaoGenerator().generateAll(schema, outDir);

    }

    private static void addEntity(Schema schema) {
        //添加一个实体,会自动生成实体类Persion
        Entity persion = schema.addEntity("Persion");
        //指定表名,如不指定,表名则为 Persion(即实体类名)
        persion.setTableName("persion");
        //给实体类中添加成员(即给表中添加列,并设置列的属性)
        persion.addIdProperty().autoincrement();//添加Id,自增长
        persion.addStringProperty("name").notNull();//添加String类型的name,不能为空
        persion.addIntProperty("age");//添加Int类型的age
        persion.addDoubleProperty("high");//添加Double类型的high
        ...
    }
}

6>运行此java类,会自动在Android项目的java-gen目录下生成bean类和DAO类:
Android ORM 框架之 greenDAO应用基础_第4张图片
Android ORM 框架之 greenDAO应用基础_第5张图片
7>转到下方 操作数据库 部分

代码说明

点击阅读greenrobot

方式二,使用注解

1>在build.gradle(app)中添加插件和依赖:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'
    }
}

apply plugin: 'org.greenrobot.greendao'

dependencies {
    compile 'org.greenrobot:greendao:3.1.0'
     // This is only needed if you want to use encrypted databases
    compile 'net.zetetic:android-database-sqlcipher:3.5.1'
    compile 'org.greenrobot:greendao-generator:3.1.0'
}

2>在build.gradle(app)中插件配置:
如果不对 greenDAO进行属性配置,在下面当”Build -> Make Project”时, greendao生成的源代码路径会是: build/generated/source/greendao。对greenDAO进行相关配置,则可以指定其路径:

greendao {
    schemaVersion 1 
    daoPackage 'com.example.greendao' 
    targetGenDir 'src/main/java' 
}

这个greendao 可以配置的属性:

schemaVersion: 数据库schema版本号,默认为1。
daoPackage: greendao生成文件 DAOs,DaoMaster,DaoSession所在的包名,默认为源码实体所在的包名。
targetGenDir: 上面包所在的路径目录,默认为:build/generated/source/greendao。
generateTests: 设置为true可以自动生成单元测试。
targetGenDirTests:生成单元测试存储在的目录, 默认为:src/androidTest/java。

3>使用注解创建Bean类:

@Entity
public class Persion {
    @Id
    private Long id;
    @NotNul
    private String name;
    private int age;
}

4>Build -> Make Project:
Make Project后,greenDAO自动为Bean类生成构造方法和每个成员的get set方法,以及前面设置的com.example.greendao包及其中的文件:
Android ORM 框架之 greenDAO应用基础_第6张图片
5>转到下方 操作数据库 部分

类注解

@Entity:注解实体类,标识一个表,添加的属性可以查阅依赖库中Entity注解类:

public @interface Entity {

    /**
     * 指定数据库中表明,默认为注解的实体类的类名
     */
    String nameInDb() default "";

    /**
     * 对实体的索引
     * 

* 注意: 如果创建单列索引使用 {@link Index} */ Index[] indexes() default {}; /** * 如果设置为false,表示这个实体类不在数据库中创建表。 仅仅是一个实体类。 * 注意,greendao不会在缓存中同步多个实体。 */ boolean createInDb() default true; /** * 指定schema名字。 */ String schema() default "default"; /** * 是否可以生成update/delete/refresh方法。 *如果实体被定义成{@link ToMany} 或者 {@link ToOne} 关系,这个属性是active */ boolean active() default false; /** * 构造器是否可以生成. */ boolean generateConstructors() default true; }

用法为:

@Entity(nameInDb="persion ",active=false)

注意:注解方式不支持多schema,但java库形式支持。

基础属性注解

@Id:对象id,通过设置@Id(autoincrement = true)表示自增,只有当Long/long时才有效

@Property:设置成员属性名(表的列名),如果不设置此属性表示默认是类成员名

@NotNull :表示此成员属性非空

@Transient:标识这个字段是自定义的,不会创建到数据库表中

自定义类型

@Convert:如果有自定义的成员类型,使用此注解。如果自定义类型或转换器是在此实体类外,需要设置她们为静态的。
使用实例:

@Entity
public class User {
    @Id
    private Long id;
    //注解中converter指向类型类,columnType指向在此表中显示的字段类型 
    @Convert(converter = RoleConverter.class, columnType = String.class)
    private Role role;

    enum Role {
        DEFAULT, AUTHOR, ADMIN
    }

    static class RoleConverter implements PropertyConverter<Role, String> {
        @Override
        public Role convertToEntityProperty(String databaseValue) {
            return Role.valueOf(databaseValue);
        }

        @Override
        public String convertToDatabaseValue(Role entityProperty) {
            return entityProperty.name();
        }
    }
}

索引注解

@Index:为数据库中此列设置为索引列,通过其name参数指定此列的索引名,通过unique参数给索引添加约束 。
@Unique:给索引添加约束。

关系注解

@ToOne:声明与另一个实体的关系:一对一。参数joinProperty 指向另一个实体的 ID列,如果不设置,则默认为id主键:

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

@ToMany:声明与另外多个实体的关系:一对多。这种关系映射有三种情况:
referencedJoinProperty 参数:外键属性,指向另一实体的ID列:

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

    @ToMany(referencedJoinProperty = "ownerId")
    private List ownedSites;
}

@Entity
public class Site {
    @Id private Long id;
    private long ownerId;
}

joinProperties 参数:对于更复杂的关系,可以使用多个@JoinProperty:

@Entity
public class User {
    @Id private Long id;
    @Unique private String authorTag;

    @ToMany(joinProperties = {
            @JoinProperty(name = "authorTag", referencedName = "ownerTag")
    })
    private List ownedSites;
}

@Entity
public class Site {
    @Id private Long id;
    @NotNull private String ownerTag;
}

@JoinEntity:多对多的关系:

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

    @ToMany
    @JoinEntity(
            entity = JoinSiteToUser.class,
            sourceProperty = "siteId",
            targetProperty = "userId"
    )
    private List authors;
}

@Entity
public class JoinSiteToUser {
    @Id private Long id;
    private Long siteId;
    private Long userId;
}

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

@Generated代码

@Generated 这个是build后greendao自动生成的,这个注解理解为防止重复,每一块代码生成后会加个hash作为标记。 官方不建议你去碰这些代码,改动会导致里面代码与hash值不符。如果手动改变引发错误:

Error:Execution failed for task ':app:greendao'.
> Constructor (see ExampleEntity:21) has been changed after generation.
Please either mark it with @Keep annotation instead of @Generated to keep it untouched,
or use @Generated (without hash) to allow to replace it.

当这个错误出现时,通常有两种方法解决:
1>恢复@Generated注解的代码,可以删除此段代码,下次build时,会再重新生成。
2>使用@Keep注解代替@Generated注解,它会告诉greenDAO不去触碰@Keep注解的代码。

操作数据库

在Android项目中自定义一个Application:

public class App extends Application {
    /** 数据库是否加密的标识 */
    public static final boolean ENCRYPTED = true;

    private DaoSession daoSession;

    @Override
    public void onCreate() {
        super.onCreate();
        //创建数据库
        DevOpenHelper helper = new DevOpenHelper(this, ENCRYPTED ? "notes-db-encrypted" : "notes-db");
        //获取数据库读写的权限,如果进行加密调用helper.getEncryptedWritableDb("super-secret"),参数为设置的密码
        Database db = ENCRYPTED ? helper.getEncryptedWritableDb("super-secret") : helper.getWritableDb();
        daoSession = new DaoMaster(db).newSession();
    }

    public DaoSession getDaoSession() {
        return daoSession;
    }
}

在Manifest文件中指向自定义的Application:

    ".App"
        ...
    

对数据库加密

在build.gradle中添加依赖:

dependencies {
    compile 'net.zetetic:android-database-sqlcipher:3.5.1'
}

如上App类,对数据库进行加密读写:

//创建数据库(上下文,数据库名)
DevOpenHelper helper = new DevOpenHelper(this,"notes-db-encrypted");
//获取读写(密码)
Database db = helper.getEncryptedWritableDb("super-secret")

如果只要求对加密的数据库进行读的操作:

//获取读(密码)
Database db = helper.getEncryptedReadableDb("super-secret")

DaoMaster和DaoSession

DaoMaster:是使用greenDAO的入口点,DaoMaster为指定的schema保存数据库对象(SQLiteDatabase)并且管理DAO类(不是对象类)。它内部的静态方法可以用来创建表或删除表,它的内部类OpenHelper 和 DevOpenHelper 是 SQLiteOpenHelper在数据库中创建schema的实现。
DaoSession:也是使用greenDAO的重要类,为指定的schema管理所有可用的DAO对象,可以使用getter方法获得DAO对象。DaoSession还提供了一些通用的持久性的方法,如插入,装载,更新,刷新和删除实体。
如果要对数据库进行操作,需要先获取相关实体类Dao对象:

daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
persionDao = daoSession.getPersionDao();

请注意,该数据库连接属于DaoMaster,所以多个Session指向的是同一个数据库。新的Session可以相当迅速的创建。每个Session都分配内存,通常为实体的一个Session“缓存”。
如果有对同一个数据库对象的多个请求,会有几个java对象来处理?这取决于作用域,默认(如果不对他进行配置)是这多个请求会返回同一个java对象,比如,查询USER 表的 ID 42 获取User对象,会为每一个请求返回相同的结果。并且会将其缓存在内存中。如果一个实体仍然存在内存中(greenDAO对它有弱引用),该实体将不会是从数据库值再次获得,例如,如果通过其ID加载实体,但是之前已经加载过这个实体,greenDAO就不会再次询问数据库了,它会从session缓存“马上”返回此对象,这样更快一个或两个数量级。

操作

1>获取DAO

        // get the note DAO
        DaoSession daoSession = ((App) getApplication()).getDaoSession();
        persionDao = daoSession.getPersionDao();

2>插入数据:id设为null,数据库会自动为其分配自增的id:

        Persion persion = new Persion(null, "liHua", 5);
        persionDao.insert(persion);

3>保存数据:如果key属性不为null,会更新这个对象;如果为null,会插入这个对象:

        Persion persion = new Persion(2, "liHua", 5);
        persionDao.save(persion);

4>查询数据:

Persion persion = persionDao.queryBuilder().where(PersionDao.Properties.Name.eq("LiHua")).build().unique();

unique()表示查询结果为一条数据,若数据不存在,persion为null。如果多个获取多个查询结果:

List persionList = persionDao.queryBuilder()  
       .where(PersionDao.Properties.Id.notEq(10)) //查询条件 
       .orderAsc(PersionDao.Properties.Id) //按首字母排列 
       .limit(10)  //限制查询结果个数
       .build().list(); //结果放进list中

5>删除数据:

persionDao.delete(persion);
//或
persionDao.deleteByKey(persion.getId()); 

6>事务:当执行的数据较多时,可以使用事务处理,事务的方法有insertInTx(~),saveInTx(~)等后缀为-InTx的方法,其参数为多个对象:

        Persion persion = new Persion(2, "liHua", 5);
        Persion persion1 = new Persion(2, "liHua", 5);
        Persion persion2 = new Persion(2, "liHua", 5);
        persionDao.saveInTx(persion,persion1,persion2);

7>更多使用方法参考greendao库中AbstractDao类。

更多参考greenDAO: Android ORM for your SQLite database

你可能感兴趣的:(Android,library)