Android ORM 框架之 greenDAO应用基础

Posted Iaouei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 等类:

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


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类:


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包及其中的文件:

5>转到下方 操作数据库 部分

类注解

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

public @interface Entity 

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

    /**
     * 对实体的索引
     * <p/>
     * 注意: 如果创建单列索引使用 @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<Site> 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<Site> 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<User> 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:

    <application
        android:name=".App"
        ...
    </application>

对数据库加密

在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<Persion> 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 ORM 框架之 greenDAO应用基础的主要内容,如果未能解决你的问题,请参考以下文章

android_orm框架之greenDAO

如何在android应用中使用greendao orm框架

[转]Android ORM系列之GreenDao最佳实践

android ORM框架--greenDao简介

android ORM框架--greenDao简介

Android:安卓学习笔记之GreenDao 的简单理解和使用