Android ORM数据库框架之-greenDao(二)
最后更新于:2022-04-01 15:49:06
这一篇将带给大家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://docs.gechiui.com/gc-content/uploads/sites/kancloud/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://docs.gechiui.com/gc-content/uploads/sites/kancloud/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/)