Realm是项目一直使用的ORM数据库框架。网络上的众多项目均采用GreenDao开发,因此学习实践一下。
一.官方文档:
http://greenrobot.org/greendao/documentation/以及Github的链接https://github.com/greenrobot/greenDAO
官方文档中还介绍了ObjectBox作为Sqlite的替代方案,性能通过官方给出的图片还是差距显著的。
二. 集成
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
implementation 'org.greenrobot:greendao:3.2.2' // add library
}
greendao {
schemaVersion 1 //数据库版本号
daoPackage 'com.fph.greendaodemo.db'// 设置DaoMaster、DaoSession、Dao 包名
targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录
}
实体类
@Entity
public class User {
@NotNull
private String name;
//id 字段必须是Long类型,默认自增
@Id
private Long id;
//... Getter/Setter等方法 通过点击 build/make project 之后来生成
}
生成的还有DaoSession、DaoMaster 和 UserDao类
初始化写在Application中
public class MyApplication extends Application {
private DaoSession daoSession;
private static MyApplication myApplication;
@Override
public void onCreate() {
super.onCreate();
initGreenDao();
myApplication = this;
}
/**
* 初始化 GreenDao
*/
private void initGreenDao() {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "test.db");
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster master = new DaoMaster(db);
daoSession = master.newSession();
}
public DaoSession getDaoSession() {
return daoSession;
}
public static MyApplication getApplication() {
return myApplication;
}
}
完成上面的工作后,写增、删、改、查的测试类
public class UserUtils {
private static final String TAG = UserUtils.class.getSimpleName();
private static UserUtils instance;
private DaoSession daoSession;
private UserDao userDao;
private UserUtils() {
initDao();
}
public static UserUtils getInstance() {
if (null == instance) {
synchronized (UserUtils.class) {
if (null == instance) {
instance = new UserUtils();
}
}
}
return instance;
}
//获取DAO
private void initDao() {
if (null == daoSession) {
daoSession = MyApplication.getApplication().getDaoSession();
}
if (null == userDao) {
userDao = daoSession.getUserDao();
}
}
//插入 若数据库中存在此id,则会报错
public void insert(User user) {
if (null != userDao && null != user) {
userDao.insert(user);
} else {
return;
}
}
//插入 若数据库中存在此id,则会更新数据
public void insertOrReplace(User user) {
if (null != userDao && null != user) {
userDao.insertOrReplace(user);
} else {
return;
}
}
//删除
public void delete(User user) {
if (null != userDao && null != user) {
userDao.delete(user);
} else {
return;
}
}
//根据id删除
public void deleteByUserId(String id) {
if (null != userDao && !TextUtils.isEmpty(id)) {
userDao.deleteByKey(Long.valueOf(id));
} else {
return;
}
}
//更新
public void update(User user) {
if (null != userDao && null != user) {
userDao.update(user);
} else {
return;
}
}
//查询所有
public List<User> query() {
if (null != userDao) {
return userDao.loadAll();
} else {
return null;
}
}
//根据id查询
public User queryById(String id) {
if (null != userDao && !TextUtils.isEmpty(id)) {
return userDao.loadByRowId(Long.valueOf(id));
} else {
return null;
}
}
//根据条件查询
public List<User> queryByArgs(String selection, String selectionArg) {
if (null != userDao && !TextUtils.isEmpty(selection)) {
return userDao.queryRaw(selection, selectionArg);
} else {
return null;
}
}
实践地址可见:https://github.com/VersaceSilva/AndroidReview/tree/master/GreenDaoTest
三. 文档探究
1. 建模实体
要在项目中使用greenDAO,您需要创建一个表示应用程序中持久数据的实体模型。然后,基于此模型,greenDAO为DAO类生成Java代码。模型本身是使用带注释的Java类定义的。
建模实体
// In the build.gradle file of your app project:
android {
...
}
greendao {
schemaVersion 2
// daoPackage "com.example.model" // set package of generated classes
}
1.1 greendao配置元素支持许多配置选项:
- schemaVersion:数据库模式的当前版本。这是使用的 * OpenHelpers类模式版本之间迁移。如果更改实体/数据库架构,则必须增加此值。默认为1。
- daoPackage:生成的DAO,DaoMaster和DaoSession的包名。 默认为源实体的包名称。
- targetGenDir:应存储生成的源的位置。 默认为构建目录( build / generated / source / greendao)中生成的源文件夹。
generateTests: 设置为true以自动生成单元测试。 - targetGenDirTests: 应存储生成的单元测试的基本目录。默认为 src / androidTest / java。
1.2 另外,可以使用@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 {
...
}
1.3 基本属性如下
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "USERNAME")
private String name;
@NotNull
private int repos;
@Transient
private int tempUsageCount;
...
}
2. Session
(生成的) DaoSession类是greenDAO的核心之一。 DaoSession为开发人员提供了对基本实体操作和DAO的访问,以实现更完整的操作集。
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
数据库连接属于 DaoMaster,因此多个Session引用相同的数据库连接。因此,可以非常快速地创建新Session。但是,每个会话分配内存,通常是实体的Session“缓存”。
如果有两个查询返回相同的数据库对象,那么您使用了多少个Java对象:一个或两个?它完全取决于身份范围。
这种副作用是某种实体“缓存”。如果实体对象仍在内存中(greenDAO在此处使用弱引用),则不再构造实体。此外,greenDAO不执行数据库查询来更新实体值。相反,该对象从会话缓存“立即”返回,该速度比一个或两个更快
如果要清除整个会话的标识范围,不要返回“缓存”对象:
daoSession.clear();
要清除单个DAO的标识范围:
noteDao = daoSession.getNoteDao();
noteDao.detachAll();
3. 查询
查询返回符合特定条件的实体。在greenDAO中,您可以使用原始SQL制定查询,或使用QueryBuilder API 更轻松地制定查询。
此外,查询支持延迟加载结果,这可能会在大型结果集上运行时节省内存和性能。
编写SQL可能很困难并且容易出现错误,这些错误仅在运行时才会被注意到。该QueryBuilder类可以让你建立你的实体,而不SQL自定义查询,并有助于在编译时已检测错误。
3.1 QueryBuilder
简单条件示例:查询名字为“Joe”的所有用户,按姓氏排序:
List<User> joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"))
.orderAsc(Properties.LastName)
.list();
嵌套条件示例:获取1970年10月或之后出生的名为“Joe”的用户。
假设我们将用户的生日作为年,月和日的单独属性。然后,我们可以表达的状态在一个更正式的方式: 首先名称是“乔” AND (一年的出生是更大的比1970年OR (一年的出生是1970年和月的诞生是等于到或大于比10 ))
(对10月10日)。
QueryBuilder<User> qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List<User> youngJoes = qb.list();
3.2 Order
您可以order查询结果。基于姓氏和出生年份的人的例子:
// 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);
greenDAO使用的默认排序规则是 COLLATE NOCASE
,但可以使用stringOrderCollation ()
进行自定义 。有关 影响结果顺序的其他方法,请参阅QueryBuilder类文档。
3.3 限制,偏移和分页
有时您只需要查询的子集,例如要在用户界面中显示的前10个元素。当您拥有大量实体并且不能仅使用“where”语句限制结果时,这尤其有用(并且足智多谋)。 QueryBuilder < T >具有定义限制和偏移的方法:
limit(int):限制查询返回的结果数。
offset(int):结合limit (int )设置查询结果的偏移量 。跳过第一个 偏移结果,结果总数将受 限制(int)限制。您不能在没有limit (int )的情况下使用offset 。
3.4 自定义类型作为参数
通常,greenDAO透明地映射查询中使用的类型。例如, boolean映射到 具有0或1值的INTEGER,而 Date映射到 (long )INTEGER 值。
自定义类型是一个例外:在构建查询时,您始终必须使用数据库值类型。例如,如果使用转换器将枚举类型映射到 int值,则应在查询中使用 int值。
更多详情见:http://greenrobot.org/greendao/documentation/queries/
4. Join
非平凡的查询通常需要几种实体类型(表)的数据。在SQL世界中,您可以通过使用连接条件“连接”两个或多个表来实现这一点。
让我们考虑一个实体 User,它与Address实体有一对多的关系 。然后,我们要查询的生活在“SeaSame Street”的用户:我们将不得不加入 地址与实体 用户使用用户ID和实体上定义一个WHERE条件 地址实体:
QueryBuilder<User> queryBuilder = userDao.queryBuilder();
queryBuilder.join(Address.class, AddressDao.Properties.userId)
.where(AddressDao.Properties.Street.eq("Sesame Street"));
List<User> users = queryBuilder.list();
连接需要目标实体类作为每个实体的参数和连接属性。在该示例中,仅定义了Address实体的join属性 ,因为默认情况下使用主键属性。换句话说,查询会产生用户,这些用户的 地址实体的 userId等于 用户实体的ID,并且还具有特定的street。
网友评论