GreenDAO 3介绍与应用

时间:2021-01-06 19:39:32

前言

当我看到需要在android工程下新建一个module-->java library的generator library的时候,便去翻阅了一下官方文档,此时发现出现了GreenDao 3,可以不用新建额外的module,而是在android工程中添加一个Gradle plugin,官方解释道:事实上,这个Gradle plugin内部也是使用原来的generator library.


Gradle Plugin简介

greenDAO 3使用新的Gradle plugin来生成代码,它会扫描所有实体以收集schema信息和生成DaoSession、DaoMaster和所有Dao类。在许多方面,greenDao的Gradle plugin可以替代generator工程,事实上,Gradle plugin内部也是使用原来的generator library。

使用Gradle plugin需要将下面配置加到我们的build script中

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

apply plugin: 'org.greenrobot.greendao'

dependencies {
compile 'org.greenrobot:greendao:3.2.0'
}

现在,我们构建项目(build project),就会执行greenDAO代码生成。也可以通过“Build>Make Project”来触发。默认生成的java代码在build/generated/source/greendao,这个目录当然可以配置。

下面我们说说,怎么配置新的Gradle plugin和怎么使用新的注解(annotation):


配置Gradle plugin

虽然说我们可以不用任何配置就能使用Gradle plugin,不过,我们至少应该设置一个schema version:

// In the build.gradle file of your app project:
android {
...
}

greendao {
schemaVersion 2
}

此外,greendao 配置还支持下面这些元素:

  • schameVersion 当前数据库schema的版本号。升级版本时用到,最小值为1,依次递增。
  • daoPackage  生成的Dao类的包名。默认是entities源文件的包名。
  • targetGenDir  生成的文件所存储的位置。默认是:build/generated/source/greendao

举例说明

greendao {
schemaVersion 1
daoPackage "com.example.greendao_demo.db.gen"
targetGenDir "src/main/java"
}

entities源文件,我放在了:

com.example.greendao_demo.db.entities



使用Annotation

greenDAO 3 uses annotations to define schemas and entities. Here is a quick example:

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

private String name;

@Transient
private int tempUsageCount; // not persisted

// getters and setters for id and user ...
}

The @Entity annotation turns the Java class User into a database-backed entity. This will also instruct greenDAO to generate the necessary code (for example DAOs).

Note: only Java classes are supported. If you prefer another language like Kotlin, your entity classes must still be Java.

The @Entity Annotation

As you saw in the example above, the @Entity annotation marks a Java class as a presistable entity for greenDAO.

While it is usually fine to go without any additional parameters, you can still configure some details using @Entity:

@Entity(
// If you have more than one schema, you can tell greenDAO
// to which schema an entity belongs (pick any string as a name).
schema = "myschema",

// Flag to make an entity "active": Active entities have update,
// delete, and refresh methods.
active = true,

// Specifies the name of the table in the database.
// By default, the name is based on the entities class name.
nameInDb = "AWESOME_USERS",

// Define indexes spanning multiple columns here.
indexes = {
@Index(value = "name DESC", unique = true)
},

// Flag if the DAO should create the database table (default is true).
// Set this to false, if you have multiple entities mapping to one table,
// or the table creation is done outside of greenDAO.
createInDb = false,

// Whether an all properties constructor should be generated.
// A no-args constructor is always required.
generateConstructors = true,

// Whether getters and setters for properties should be generated if missing.
generateGettersSetters = true
)
public class User {
...
}

Note that multiple schemas are currently not supported when using the Gradle plugin. For the time being, continue to use your generator project.

Basic properties

@Entity
public class User {
@Id(autoincrement = true)
private Long id;

@Property(nameInDb = "USERNAME")
private String name;

@NotNull
private int repos;

@Transient
private int tempUsageCount;

...
}

The @Id annotation selects a longLong property as the entity ID. In database terms, it’s the primary key. The parameter autoincrement is a flag to make the ID value ever increasing (not reusing old values).

@Property lets you define a non-default column name, which the property is mapped to. If absent, greenDAO will use the field name in a SQL-ish fashion (upper case, underscores instead of camel case, for example customName will become CUSTOM_NAME). Note: you currently can only use inline constants to specify a column name.

@NotNull makes the property a “NOT NULL” column on the database side. Usually it makes sense to mark primitive types (long, int, short, byte) with @NotNull, while having nullable values with wrapper classes (Long, Integer, Short, Byte).

@Transient marks properties to be excluded from persistence. Use those for temporary states, etc. Alternatively, you can also use the transient keyword from Java.

Primary key restrictions

Currently, entities must have a long or Long property as their primary key. This is recommended practice for Android and SQLite.

To work around this, define your key property as an additional property, but create a unique index for it:

@Id
private Long id;

@Index(unique = true)
private String key;

Property indexes

Use @Index at a property to create a database index for the corresponding database column. Use the following parameters to customize:

  • name: If you do not like the default name greenDAO generates for the index, you can specify yours here.
  • unique: Adds a UNIQUE constraint to the index, forcing all values to be unique.

@Entity
public class User {
@Id private Long id;
@Index(unique = true)
private String name;
}

@Unique adds a UNIQUE constraint to the database column. Note, that SQLite also implicitly creates an index for it.

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

Defaults

greenDAO tries to work with reasonable defaults, so developers don’t have to configure each and every bit.

For example the table and column name on the database side are derived from the entity and property names. Instead of the camel case style used in Java, the default database names are in uppercase using an underscore to separate word.

For example, a property called creationDate will become a database column CREATION_DATE.

Relations

To learn how to add to-one and to-many relations see Relations.

Triggering generation

Once your entity schema is in place, you can trigger the code generation process by using “Make project” in your IDE. Or by directly executing the greendao Gradle task.

If you encounter errors after changing your entity classes, try to rebuild your project to make sure old generated classes are cleaned.

Modifying generated code

Entity classes in greenDAO 3 are created and edited by the developer. However, during the code generation process greenDAO may augment the source code of entities.

greenDAO will add a @Generated annotation to methods and fields it created, to inform the developer and to prevent any loss of code. In most cases, you should not have to touch code annotated with @Generated.

As a precaution, greenDAO will not overwrite existing code and raise an error if generated code was manually changed:

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.

As the error message implies, there are usually two ways to resolve this:

  • Revert the changes to code annotated with @Generated. Alternatively, you can also delete the changed constructor or method completely. They will be regenerated with the next build.
  • Replace the @Generated annotation with a @Keep annotation. This will tell greenDAO to never touch the annotated code. Keep in mind that your changes might break the contract between the entity and the rest of greenDAO. Also, future releases of greenDAO might expect different code in generated methods. So, be cautious! It’s a good idea to have unit tests in place to avoid trouble.

Keep sections

KEEP sections used in older versions of greenDAO are no longer supported.

However, if the Gradle plugin detects a KEEP FIELDS section it will automatically annotate fields inside with @Transient. Afterwards, the surrounding KEEP FIELDS comments may be removed.