ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
这一篇将带给大家greenDao的一些比较高级的用法。 以下内容参考[官网](http://greendao-orm.com/) 关系型数据库,当然少不了多表关联,SQLite也不例外。那么我们就下来看下greenDao如何建立表关联 - 一对一 1:1 entity.addToOne(entity,property) 我们以人和身份证为例, ~~~ /** * 人实体 */ Entity people = schema.addEntity("People"); people.addStringProperty("name").primaryKey(); //名字 people.addIntProperty("age"); //年龄 /** * 身份证 */ Entity idcard = schema.addEntity("IdCard"); idcard.addStringProperty("idcardnum").primaryKey(); //身份证号 /** * 人和身份证 是一对一的关系 */ /** 一个人对应一个idcard **/ Property propertyidcardnum = people.addStringProperty("idcardnum").getProperty(); people.addToOne(idcard, propertyidcardnum); /** 一个idcrad 对应一个name ***/ Property propertyname = idcard.addStringProperty("name").getProperty(); idcard.addToOne(people, propertyname); ~~~ 注意:当我们要建立多表关联的时候,就不在添加id主键了,以为我们这里的主键要当成其他表的外键使用。 上面我们通过entity.addToOne(otherEntity,peoperty)来建立一对一关联,关系为,entity和otherentity通过peroperty来建立关联,其中peoperty在otherentity中式主键,在entity中是外键。这么干说,谁也记不住。看代码 ~~~ Property propertyidcardnum = people.addStringProperty("idcardnum").getProperty(); people.addToOne(idcard, propertyidcardnum); ~~~ 我们将身份证实体中的主键idcardnum,当成外键以一对一的关系添加到people实体中了,就是这么简单。 - 一对多 1:n addToMany(entity,property) ~~~ Entity order = schema.addEntity("Order"); order.addIntProperty("orderid").primaryKey(); order.addDoubleProperty("money").notNull(); /** * 建立人与订单的一对多关系 */ // Property propertypeoplenum=people.addStringProperty("idcardnum").getProperty(); Property property = order.addStringProperty("name").getProperty(); order.addToOne(people, property); people.addToMany(order,propertyname).setName("orders"); ~~~ 我在这里建立了一个购物的实体。形成一对多关系 。并将订单中的主键id,以多对一的形式给people当外键。 - 多对多 m:n ~~~ Entity course = schema.addEntity("Course"); course.addStringProperty("courseid").primaryKey(); course.addStringProperty("coursename").notNull(); Property propertyPeopleId = course.addStringProperty("name").getProperty(); course.addToMany(people,propertyPeopleId); Property propertyCourseID = people.addStringProperty("courseid").getProperty(); people.addToMany(course,propertyCourseID); ~~~ ,这个就和上面的一样了,我就不再多少了。 需要注意的是,这里的关系特别绕,一不小心就会弄错。 现在,我们去看看生成的实体类有什么区别。 先看People,我们还记得,和身份证是一对一,和订单是一对多,和课程是多对多。 ~~~ private String name; private Integer age; private String idcardnum; private String courseid; /** Used to resolve relations */ private transient DaoSession daoSession; /** Used for active entity operations. */ private transient PeopleDao myDao; private IdCard idCard; private String idCard__resolvedKey; private List<Order> orders; private List<Course> courseList; ~~~ 看到没,成员变量这里有了IdCard(单一),List< Order> ,List< Course >,确实是形成了上面我们写的关系。 接下来我们看下构造函数 ~~~ public People(String name, Integer age, String idcardnum, String courseid) { this.name = name; this.age = age; this.idcardnum = idcardnum; this.courseid = courseid; } ~~~ 构造函数里面只是几个相关表的主键。。没什么奇怪的。那么我们看下,这个类下面都有什么方法。 ![](https://box.kancloud.cn/2016-04-08_5707680675d40.jpg "") 有发现,我们会发现这里面有getCourseList 和 getOrderList,我们挑一个来看看 ~~~ public List<Order> getOrders() { if (orders == null) { if (daoSession == null) { throw new DaoException("Entity is detached from DAO context"); } OrderDao targetDao = daoSession.getOrderDao(); List<Order> ordersNew = targetDao._queryPeople_Orders(name); synchronized (this) { if(orders == null) { orders = ordersNew; } } } return orders; } ~~~ 看到,这里通过name来查询,为什么呢?因为我们这个name是Order表的外键。哈哈,这样就爽了,都直接给提供方法了,都不同我们自己搞。恩,确实爽。 我们再看看_queryPeople_Orders()方法 ~~~ public List<Order> _queryPeople_Orders(String name) { synchronized (this) { if (people_OrdersQuery == null) { QueryBuilder<Order> queryBuilder = queryBuilder(); queryBuilder.where(Properties.Name.eq(null)); people_OrdersQuery = queryBuilder.build(); } } Query<Order> query = people_OrdersQuery.forCurrentThread(); query.setParameter(0, name); return query.list(); } ~~~ 不粗,果然是给我们封装好了的。啥,这种查询方法,看不懂?没事,我们后面会介绍到。 多表关联我们看完了,这里你要注意一个坑,那就是 关联的2张表的主键类型一定要一样,别问我为什么。 - 其他用法 添加约束 无非就是添加 主键 非空 自增等等。 ![](https://box.kancloud.cn/2016-04-08_57076806900f2.jpg "") 如: ~~~ order.addIntProperty("orderid").primaryKey(); ~~~ 多线程下 ~~~ Query<Order> query = people_OrdersQuery.forCurrentThread(); ~~~ 多条件查询 ~~~ 名字叫“乔”和(出生年份大于1970或(出生年份是1970年,出生月等于或大于10(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(); ~~~ 或者 ~~~ Query query = userDao.queryBuilder().where( Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)) .build(); List joesOf1970 = query.list(); ~~~ 或者 ~~~ query.setParameter(0, "Maria"); query.setParameter(1, 1977); List mariasOf1977 = query.list(); ~~~ 嵌套查询 ~~~ Query query = userDao.queryBuilder().where( new StringCondition("_ID IN " + "(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build(); ~~~ 链接查询 ~~~ 使用连接查询 查询用户名为admin Query query = userDao.queryRawCreate( ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin"); ~~~ 我们再来看看query的几个list…方法 > list() 所有的实体都被加载到内存中,结果是一个ArrayList,比较容易使用 listLazy() 实体按照需求加载,并不会查询完立即加载进内存,只会在需要的时候加载,并且会缓存在一个list之中,并需调用close关闭 listLazyUnCached() 一个虚拟的实体集,任何访问都必须从数据库中加载,必须被关闭 listIterator() 让你便利加载,数据没有被缓存,必须关闭 代码混淆 ~~~ -keepclassmembers class * extends de.greenrobot.dao.AbstractDao { public static java.lang.String TABLENAME; } -keep class **$Properties ~~~ 或者去github上看他们demo如何混淆的。 - 数据库升级 本以为这么好个东西数据库升级的一些问题肯定也弄好了,哎,结果。多说无益,我们来看看他封装的代码把。 ~~~ DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,"persons-db",null); ~~~ ~~~ public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name, CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); dropAllTables(db, true); onCreate(db); } } ~~~ ~~~ public static void dropAllTables(SQLiteDatabase db, boolean ifExists) { PersonDao.dropTable(db, ifExists); PeopleDao.dropTable(db, ifExists); IdCardDao.dropTable(db, ifExists); OrderDao.dropTable(db, ifExists); CourseDao.dropTable(db, ifExists); } ~~~ ~~~ public static void dropTable(SQLiteDatabase db, boolean ifExists) { String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"PERSON\""; db.execSQL(sql); } ~~~ 看见没,根本没有所谓的数据库升级,还把原来的数据库给删除了。擦。那怎么办呢。别着急,虽然咱垃圾,但是思路还是有的, 怎么办呢? 第一步,我们在生成生成实体类的文件中。 ~~~ schema.enableKeepSectionsByDefault();//通过次Schema对象添加的所有实体都不会覆盖自定义的代码 或者根据需要添加其他() ~~~ 这样我们再生成的时候就不会覆盖了。 第二步,咱给出一个连接,你们看吧。(本屌太渣) [greenDao数据库升级](http://blog.csdn.net/fancylovejava/article/details/46713445) 到此为止: 参考资料:[greenDao官网](http://greendao-orm.com/)