GreenDao (2.1.0 反射机制) 初步使用
参考文档:
1.什么是GreenDao?为什么要用GreenDao?
简单的讲,greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。
==个人理解: 就是将 SQlite 中的列 转换为对象 的属性来操作。多表关联就是 该对象A(—-包含外键) 中可以获取别的对象B(B 中主键关联 A 的外键)==。
备注: ORM:Object Relation Mapping - 对象关系映射
对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换[1] 。从效果上说,它其实是创建了一个可在编程语言里使用的–“虚拟对象数据库”。
2. 步骤
1. GreenDao 映射生成DAO
- 建java lib工程
- 导包依赖 compile ‘de.greenrobot:greendao-generator:2.1.0’
- 创建schema
Schema schema=new Schema(1---版本,"hyldemo"---设置对象的 文件夹名称);
/*设置dao包默认的位置*/
schema.setDefaultJavaPackageDao("com.guangda.dao");
- 创建entity
Entity user = schema.addEntity("User");-----创建 user 表
user.implementsSerializable();-----多表关联前需序列号
user.addIdProperty();----添加主键
user.addStringProperty("age").notNull();---添加列 并 非空
Property infoId = user.addLongProperty("infoId").getProperty();-----添加外键
- 生成DAO文件
new DaoGenerator().generateAll(schema, "app/src/main/java-gen");----生成 dao 文件位置
2.GreenDao 在项目中的使用步骤
- 创建android 工程
- 配置Appliction 官方推荐在 app 初始化的时候进行 配置
- 配置 build.gradle
sourceSets{
main{
java.srcDirs = ['src/main/java', 'src/main/java-gen']
}
}
compile 'de.greenrobot:greendao:2.1.0'
- 使用
增
private UserDao getUserDao(){
return ((BaseApplication)this.getApplicationContext()).getDaoSession().getUserDao();
}--------------获取对 userdao 的引用
User user = new User(null, "你真帅", "18age", "12334556778", "天为被地为床", true,null);
getUserDao().insert(user);
查
QueryBuilder
特点: QueryBuilder很容易使用,节省了你书写SQL语句的时间。当然,由于语法的检验是在编译时才执行,所以在查询语句中发现bug是很困难的。
查询first name是Joe,并在1970年10月以及之后的所有人:
QueryBuilder 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 youngJoes = qb.list();
Lazylist
特点: greenDAO支持返回唯一查询结果(如果没有返回null) —- 调用Query或QueryBuilder的unique()方法;
也支持返回list —- 调用list()方法。
当不希望返回null作为结果时,则调用uniqueOrThrow()方法,当结果null时将直接抛出异常。常用方法
list(): 所有entity均会被加载到内存中。结果仅是一个简单的ArrayList。使用最简单。
listLazy(): 查询结果会根据需要加载到内存中。列表中的元素仅在accessed for the first time,它才会被加载并缓存。该方法必须主动关闭(Must be closed)。
listLazyUncached(): 虚拟的结果列表,任何对元素的方法实际都会到数据库中去加载数据。Must be closed
listIterator(): 根据需要迭代结果(lazily)。数据不缓存。Must be closed
Query
特点:Query类代表了一个可以被重复执行的查询。在QueryBuilder内部其实也是会定义一个Query并执行完成查询。
这将带来极大地方便,因为任何人都不希望在每次查询的时候总是写一遍query代码。同时Query还可以根据需要改变参数
使用Query对象查询名为Joe并出生在1970年的人:
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
.build();
List joesOf1970 = query.list();
然后想再查询出生在1977年之后并叫Marias的人:
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
其他:原生sql查询。。。
删除
dbService.getDaoSession().getUserDao().delete( new User(ll));
dbService.getDaoSession().getUserDao().deleteByKey(ll---主键);
改
eg.userDao.insertOrReplace(user);
- 多表关联
一对一
在 GreenDao 中实现一对一的关联需要讲一个实体类的主键作为另一个实体类的外键。
比如一个 Person 有一个 IDCard(身份证),这两者是一一对应的关系,同时,Person 有 name(主键)、sex 和 age 三个属性,
IDCard 有 CardId 和 CardId(主键) 和 Validity 两个属性。
那么可以将 Person 的主键作为 IDCard 的外键,将 IDCard 的主键作为 Person 的外键:
Entity person = schema.addEntity("Person");
person.addStringProperty("name").primaryKey();
person.addStringProperty("sex");
person.addLongProperty("age");
Entity idCard = schema.addEntity("IDCard");
idCard.addLongProperty("cardId").primaryKey();
idCard.addLongProperty("validity");
// 两个实体类通过 Property 来建立关联,此操作会在 person 表中增加一个外键,此外键是 idCard 表中的主键
Property personProperty = person.addLongProperty("cardId").getProperty();
// 第一个参数为目标实体类,第二个参数为此表中的外键属性
person.addToOne(idCard, personProperty);
Property idCardProperty = idCard.addStringProperty("name").getProperty();
idCard.addToOne(person, idCardProperty);
一对多
Entity order = schema.addEntity("Order");
order.addLongProperty("orderId").primaryKey();
order.addLongProperty("money").notNull();
Property orderProperty = order.addStringProperty("name").getProperty();
// 构建一对多的关联
// 第一个参数为目标实体,第二个参数为目标属性,也就是 person 的主键(order 的外键),第三个参数为属性名
person.addToMany(order, orderProperty, "orders");
// 订单对用户为一对一的关联
order.addToOne(person, orderProperty);
多对多
GreenDao 不支持多对多的关系,但是,我们可以通过其它方法来实现。
实现多对多关联需要建立一张中间表,其它两张表都要与中间表构建一对多的关联。
比如学生与课程之间的连系,一个学生可以选择多种课程,而一个课程可以被多个学生选择
Entity course = schema.addEntity("Course");
course.addLongProperty("courseId").primaryKey();
course.addStringProperty("courseName").notNull();
// 中间表有其它两个表的主键作为外键
Entity personCourse = schema.addEntity("PersonCourse");
Property personName = personCourse.addStringProperty("name").getProperty();
Property courseId = personCourse.addLongProperty("courseId").getProperty();
// 分别构建一对多的关联
person.addToMany(personCourse, personName);
course.addToMany(personCourse, courseId);
personCourse.addToOne(person, personName);
personCourse.addToOne(course, courseId);
示例代码
- javalib
compile ‘de.greenrobot:greendao-generator:2.1.0’
public class MyClass {
public static void main(String[] args) throws Exception {
// 正如你所见的,你创建了一个用于添加实体(Entity)的模式(Schema)对象。
// 两个参数分别代表:数据库版本号与自动生成代码的包路径。
Schema schema=new Schema(1,"greendaohyl");
/*设置dao包默认的位置*/
schema.setDefaultJavaPackageDao("com.guangda.dao");
// 一旦你拥有了一个 Schema 对象后,你便可以使用它添加实体(Entities)了。
/*建表--添加实体*/
addUser(schema);
// 最后我们将使用 DAOGenerator 类的 generateAll() 方法自动生成代码,此处你需要根据自己的情况更改输出目录(既之前创建的 java-gen)。
// 其实,输出目录的路径可以在 build.gradle 中设置,有兴趣的朋友可以自行搜索,这里就不再详解。
new DaoGenerator().generateAll(schema,"app/src/main/java-gen");
/*"app/src/main/java-gen"+*/
}
/* info 信息表里面有 user 信息 info 里面有 外键与 user 关联*/
private static void addUser(Schema schema) {
// 一个实体(类)就关联到数据库中的一张表,此处表名为「User」(既类名)
Entity user = schema.addEntity("User");
user.implementsSerializable();
// 你也可以重新给表命名
// note.setTableName("NODE");
// greenDAO 会自动根据实体类的属性值来创建表字段,并赋予默认值
// 接下来你便可以设置表中的字段:
user.addIdProperty();
user.addStringProperty("name").notNull();
// 与在 Java 中使用驼峰命名法不同,默认数据库中的命名是使用大写和下划线来分割单词的。
// For example, a property called “creationDate” will become a database column “CREATION_DATE”.
user.addStringProperty("age").notNull();
user.addStringProperty("tel").notNull();
user.addStringProperty("location");
user.addBooleanProperty("isRun");
Entity info = schema.addEntity("Info");
info.implementsSerializable();
info.addIdProperty();
info.addStringProperty("zhiwei").notNull();
// 与在 Java 中使用驼峰命名法不同,默认数据库中的命名是使用大写和下划线来分割单词的。
// For example, a property called “creationDate” will become a database column “CREATION_DATE”.
info.addStringProperty("gangwei").notNull();
info.addBooleanProperty("issave");
//这里我们为user 表,添加一个infoId外键,它就是info表的id
Property infoId = user.addLongProperty("infoId").getProperty();
//这里是重点,我们为这两个表建立1:n的关系,并设置关联字段。
user.addToOne(info, infoId);
ToMany addToMany = info.addToMany(user,infoId);
addToMany.setName("infoes");
}
}
- BaseApplication
compile ‘de.greenrobot:greendao:2.1.0’
public class BaseApplication extends Application {
private static BaseApplication mInstance;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
private static SQLiteDatabase db;
@Override
public void onCreate() {
super.onCreate();
if (mInstance == null)
mInstance = this;
}
//
// private void setupDataBase() {
// // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。
// // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。
// // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
// // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
db = helper.getWritableDatabase();
// 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
// /*创建数据库文件 获取数据库对象 db通过帮助实例,获取数据库, 此时会调用 帮助类中的 onCreate 方法*/
// DaoMaster.OpenHelper helper = new THDevOpenHelper(this, "hyldb", null);
// db = helper.getWritableDatabase();
// /*该数据库 连接 DaoMaster 所以多个 Session 指的是相同的数据库连接*/
// daoMaster = new DaoMaster(db);
// daoSession = daoMaster.newSession();
//
// }
public static SQLiteDatabase getDb(Context context) {
if (db == null) {
DaoMaster.OpenHelper helper = new THDevOpenHelper(context, "myDb", null);
db = helper.getWritableDatabase();
}
return db;
}
public static DaoMaster getDaoMaster(Context context) {
if (daoMaster == null) {
daoMaster = new DaoMaster(getDb(context));
}
return daoMaster;
}
/*获取UserDao 对象 进行 增删改查 */
public static DaoSession getDaoSession(Context context) {
if (daoSession == null) {
if (daoMaster == null) {
daoMaster = getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
public static BaseApplication getApp() {
return mInstance;
}
}
- DeServer
public class DbService {
private static DbService instance;
private static Context appContext;
private DaoSession mDaoSession;
private InfoDao mInfoDao;
private UserDao userDao;
private DbService() {
}
/**
* 采用单例模式
* @param context 上下文
* @return dbservice
*/
public static DbService getInstance(Context context) {
if (instance == null) {
instance = new DbService();
if (appContext == null){
appContext = context.getApplicationContext();
}
instance.mDaoSession = BaseApplication.getDaoSession(context);
instance.userDao = instance.mDaoSession.getUserDao();
instance.mInfoDao=instance.mDaoSession.getInfoDao();
}
return instance;
}
/* 增的方法*/
/**
* 根据用户信息,插件或修改信息
* @param user 用户信息
* @return 插件或修改的用户id
*/
public long saveUser(User user){
return userDao.insertOrReplace(user);
}
public long saveInfo(Info info){
return mInfoDao.insertOrReplace(info);
}
/**
* 取出所有数据
* @return 所有数据信息
*/
public List<User> loadAllUser(){
return userDao.loadAll();
}
/**
* 删除所有数据
*/
public void deleteAllUser(){
userDao.deleteAll();
}
public void deleterUser(Long id){
userDao.deleteByKey(id);
}
/*级联查询*/
public DaoSession getDaoSession(){
return mDaoSession;
}
/**
* 根据查询条件,返回数据列表
* @param where 条件
* @param params 参数
* @return 数据列表
*/
public List<User> queryNote(String where, String... params){
return userDao.queryRaw(where, params);
}
}
- THDevOpenHelper
public class THDevOpenHelper extends DaoMaster.OpenHelper {
public THDevOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
switch (i) {
case 2:
//创建新表,注意createTable()是静态方法
UserDao.createTable(db, true);
InfoDao.createTable(db,true);
// 加入新字段
// db.execSQL("ALTER TABLE 'moments' ADD 'audio_path' TEXT;");
break;
}
}
}
- 具体
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private int i=0;
private DbService dbService;
private Long l=0l;
private EditText et;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt_add= (Button) findViewById(R.id.bt_add);
Button bt_del= (Button) findViewById(R.id.bt_del);
Button bt_sel= (Button) findViewById(R.id.bt_sel);
Button bt_update= (Button) findViewById(R.id.bt_update);
et = (EditText) findViewById(R.id.et);
bt_add.setOnClickListener(this);
bt_del.setOnClickListener(this);
bt_sel.setOnClickListener(this);
bt_update.setOnClickListener(this);
dbService = DbService.getInstance(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt_add:
i++;
l++;
User user = new User(null, "你真帅"+(i), "18age", "12334556778", "天为被地为床", true, l);
DbService.getInstance(this).saveUser(user);
Info info = new Info(null, "董事长"+(i), "总经理", true);
DbService.getInstance(this).saveInfo(info);
List<User> users = DbService.getInstance(this).loadAllUser();
for (User user1 : users) {
Toast.makeText(this, "rl点击了" + user1.getName(), Toast.LENGTH_SHORT).show();
}
break;
case R.id.bt_sel:
// User user1 = new User(null, "你怎么越来越帅啊。。", "永远的18age", "1230612306", "天为被,地为床", false, 1L);
// DbService.getInstance(this).saveUser(user1);
QueryBuilder qb = DbService.getInstance(this).getDaoSession().getUserDao().queryBuilder();
List<User> youngJoes = qb.list();
for (User youngJoe : youngJoes) {
// Toast.makeText(this, "bt点击了" + youngJoe.getId()+"----"+youngJoe.getName()+"----"+youngJoe.getInfoId()+"------"+youngJoe.getInfo().getZhiwei().toString(), Toast.LENGTH_SHORT).show();
Log.e("sel-----------------",youngJoe.getId()+"----"+youngJoe.getName()+"----"+youngJoe.getInfoId()+"----"+youngJoe.getTel());
/*+youngJoe.getInfo().getZhiwei().toString()*/
}
break;
case R.id.bt_del:
long ll=Long.valueOf(et.getText().toString().trim());
// dbService.getDaoSession().getUserDao().deleteByKey(ll);
//
dbService.getDaoSession().getUserDao().delete( new User(ll));
break;
case R.id.bt_update:
long lll=Long.valueOf(et.getText().toString().trim());
User us = new User(lll, "你真帅"+(i), "18age", "天道酬勤,上善若水", "天为被地为床", true, l);
dbService.getDaoSession().getUserDao().insertOrReplace(us);
// dbService.getDaoSession().getInfoDao().load(lll).update();
break;
default:
break;
}
}
}
其他
DaoMaster:
是GreenDao的入口也是greenDao顶级对象,对于一个指定的表单持有数据库对象(SQLite数据库)并且能够管理DAO类
能够创建表和删除表
其内部类OpenHelper 与DevOpenHelper是创建SQlite数据库的SQLiteOpenHelper的具体实现
DaoSession:
对于一个指定的表单可以管理所有的Dao 对象。
也能够对实体类执行 insert ,load,update,refresh.delete操作。
DaoSession也能跟踪 identity scope:即session查询后的实体会存在缓存中,并给该实体生成一个flag来追踪该实体,下次再次查询时会直接从缓存中取出来而不是从数据库中取出来
DAOS
能够持久访问和查询实体类
比起DaoSession有更多的持久化方法 count, loadAll,insertInt等等;
Entities - 自动生成的代码,一般情况下与javaBean对象的属性一一对应。
基本注释属性
@ID 一般会选择long/Long属性作为Entity ID(即数据库中的主键)autoincrement=true表示主键会自增如果false就会使用旧值
@Property 可以自定义一个该属性在数据库中的名称,默认情况下数据库中该属性名称是Bean对象中的 属性名但是不是以驼峰式而是以大写与下划线组合形式来命名的比如:customName将命名为 CUSTOM_NAME;注意:外键不能使用该属性;
@NotNull 确保属性值不会为null值;
@Transient 使用该注释的属性不会被存入数据库中;
@Unique 将属性变成唯一约束属性;也就是说在数据库中该值必须唯一
@Generated 提示开发者该属性不能被修改;并且实体类的方法,属性,构造器一旦被@Generated注释就不能被再次修改,否则或报错
eq():==
noteq():!=
gt(): >
lt():<
ge:>=
le:<=
like():包含
between:俩者之间
in:在某个值内
notIn:不在某个值内