Realm学习(二)
首先,realm1.0.0发布了
这次打算按照使用顺序来扯扯:Rx大法好!
一、配置
建议最好是在Application中设置统一配置,这样方便在整个app中使用,虽说允许差异化创建,但是刚开始还是统一比较好,代码如下:
RealmConfiguration configuration = new RealmConfiguration.Builder(this).name("collection.realm")//配置文件名.schemaVersion(1) //数据库版本.migration(new MyMigration()) //版本发生迁移时的处理类.encryptionKey(new byte[64]) //用来加密数据库.modules("ad") //没搞明白//.inMemory() //在内存中创建realm来使用,通用配置不需要该项.build();
Realm.setDefaultConfiguration(configuration);
使用时获取默认配置就很简单了:
realm = Realm.getDefaultInstance();
Realm使用后必须关闭,而且realm是各管各的,所以用几次就需要关闭几次。
例如activity中可以将realm的关闭放在onDestroy()中:
@Override
protected void onDestroy() {super.onDestroy();if(realm!=null&&!realm.isClosed())realm.close();
}
在try-catch-finally的finally中保证最后能执行realm的关闭。
二、模型
这里的模型相当于一张数据库的table。
在之前的版本中,RealmObject中只支持private成员变量,现在扩大了public、protected;而且现在支持在getter和setter中自定义成员方法。
还可以定义public变量后直接使用。
内部的成员变量就相当于数据表中的属性列,所以这里会有几个跟数据相关的几个注解:
@PrimaryKey 标注主键,不可空,不可重复, 支持String,short,int,long,Short,Int,Long七种。
@Required 强制不为空,不适用于基本类型;
@Ignore 有用但是不往数据库存,例如购物车选中某件商品的总价是有意义的,但是对于数据库重要的是数量和单价,总价就没太大意义;
@Index 提升查询速度,压制其他速度;
继承RealmObject的对象和List<RealmObject>也可以作为一个成员写在另一个realm实体中如:
public class GroupEntity extends RealmObject {@PrimaryKeypublic String id;public String name;public int color;
}public class ContactEntity extends RealmObject {@PrimaryKeyprivate int id;private String name;private GroupEntity group;
}
创建模型对象:
由于 Realm 对象都强依赖于 Realm,它们应该直接通过 Realm 被实例化,这个是比较提倡的使用方式;也可以为该模型添加构造器,通过构造方法像普通的类一样使用,但是这里有一个要求,必须包含一个无参构造器(因为通过Realm实例化的时候需要默认无参构造器)。这里我直接使用官方文档的示例了:
realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("john@corporation.com");
realm.commitTransaction();
User user = new User("John");
user.setEmail("john@corporation.com");
三、事务
1.查询
Realm的查询是比较方便的,支持链式调用(好像应该叫函数式)并且不是必须包含在事务中。
Realm realm = Realm.getDefaultInstance();RealmResults<GroupEntity> results = realm.where(GroupEntity.class).findAll();
如上代码,获取到realm对象后就可以进行查询操作了。
接下来说个牛逼的:级联查询
接触过数据库的兄弟姐妹们都知道两张表连在一起查询的时候简直烦到死,什么左联右联;使用外键id对应的名称时得两次查询......反正是一堆苦水啊。
当你使用realm的时候,如上面提到过的两个关联的表,如果想根据groupEntity的某个字段的值来获取ContactEntity的数组,而该字段在ContactEntity中没有直接关系,就可以这样写了:
RealmResults<ContactEntity> entities = realm.where(ContactEntity.class).equalTo("group.name",name)//”当前列名.关联列名”的形式.findAll();
如果是其他的数据库,这里就需要先查到name对应的groupid,根绝groupid再来查询ContactEntity表.....Realm关联查询就是这么简单,好用到爆!
支持的查询条件:
·between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
·equalTo() 和 notEqualTo()
·contains()、beginsWith() 和 endsWith()
·isNull() 和 isNotNull()
·isEmpty() 和 isNotEmpty()
·or()和and()
·not()
·sort()//排序
2.写入(必须包含进事务)
写入包括增删改三个方面。
使用事务由两种方式
方式一、
realm.beginTransaction();
//写入操作
realm.commitTransaction();
//realm.cancelTransaction() //发生错误时可以取消操作
方式二、
realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {//写入操作}});
异步事务的方式就是方式二的方法名多了几个字符Asyn(OnSuccess和OnError是可选重载项)
realm.executeTransactionAsync(new Realm.Transaction() {@Overridepublic void execute(Realm bgRealm) {User user = bgRealm.createObject(User.class);user.setName("John");user.setEmail("john@corporation.com");}}, new Realm.Transaction.OnSuccess() {@Overridepublic void onSuccess() {// Transaction was a success.}}, new Realm.Transaction.OnError() {@Overridepublic void onError(Throwable error) {// Transaction failed and was automatically canceled.}});
注意:异步事务调用会返回一个 RealmAsyncTask 对象。当你退出 Activity 或者 Fragment 时可以使用该对象取消异步事务。如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃。
public void onStop () {if (transaction != null && !transaction.isCancelled()) {transaction.cancel();}}
四、版本变迁:
1.忽略变迁:
直接在配置中添加就行:
RealmConfiguration config = new RealmConfiguration.Builder(context).deleteRealmIfMigrationNeeded().build()
接下的处理方式建议放在RealmMigration的实现类中,因为匿名内部类在多版本的情况下结构上看起来会很夸张,不方便阅读。
新建类继承RealmMigration,添加默认方法的实现:
void migrate(DynamicRealm realm, long oldVersion, long newVersion);
DynamicRealm :继承自BaseRealm的动态的Realm对象,通过它来完成迁移的任务。
2.添加新表:
这个时候,数据库的结构会发生变化,所以需要一个架构级的对象来进行操作,这里需要首先获取一个RealmSchema 对象:
RealmSchema schema = realm.getSchema();
Schema可以看作是一个库级的可操作对象。
然后是对对应版本做相对处理:
if (oldVersion==2){schema.create("Contact").addField("name",String.class)//对象名称和类型.addField("id",int.class, FieldAttribute.INDEXED)//可以制定约束.addField("url",String.class).addField("pinyin",String.class).addField("firstChar",String.class);oldVersion++;
}
3.修改已有表:
if (oldVersion==3){schema.get("Contact").addField("group",String.class).addRealmObjectField("favoriteDog", schema.get("Dog"))//RealmObj数据.addRealmListField("dogs", schema.get("Dog"))//List<RealmObj>数据.renameField("url","lru")//修改列名.removeField("url");//删除列oldVersion++;
}
4.删除表:
if(oldVersion==4){schema.remove("Contact");//删除表
}
Realm学习(二)
首先,realm1.0.0发布了
这次打算按照使用顺序来扯扯:Rx大法好!
一、配置
建议最好是在Application中设置统一配置,这样方便在整个app中使用,虽说允许差异化创建,但是刚开始还是统一比较好,代码如下:
RealmConfiguration configuration = new RealmConfiguration.Builder(this).name("collection.realm")//配置文件名.schemaVersion(1) //数据库版本.migration(new MyMigration()) //版本发生迁移时的处理类.encryptionKey(new byte[64]) //用来加密数据库.modules("ad") //没搞明白//.inMemory() //在内存中创建realm来使用,通用配置不需要该项.build();
Realm.setDefaultConfiguration(configuration);
使用时获取默认配置就很简单了:
realm = Realm.getDefaultInstance();
Realm使用后必须关闭,而且realm是各管各的,所以用几次就需要关闭几次。
例如activity中可以将realm的关闭放在onDestroy()中:
@Override
protected void onDestroy() {super.onDestroy();if(realm!=null&&!realm.isClosed())realm.close();
}
在try-catch-finally的finally中保证最后能执行realm的关闭。
二、模型
这里的模型相当于一张数据库的table。
在之前的版本中,RealmObject中只支持private成员变量,现在扩大了public、protected;而且现在支持在getter和setter中自定义成员方法。
还可以定义public变量后直接使用。
内部的成员变量就相当于数据表中的属性列,所以这里会有几个跟数据相关的几个注解:
@PrimaryKey 标注主键,不可空,不可重复, 支持String,short,int,long,Short,Int,Long七种。
@Required 强制不为空,不适用于基本类型;
@Ignore 有用但是不往数据库存,例如购物车选中某件商品的总价是有意义的,但是对于数据库重要的是数量和单价,总价就没太大意义;
@Index 提升查询速度,压制其他速度;
继承RealmObject的对象和List<RealmObject>也可以作为一个成员写在另一个realm实体中如:
public class GroupEntity extends RealmObject {@PrimaryKeypublic String id;public String name;public int color;
}public class ContactEntity extends RealmObject {@PrimaryKeyprivate int id;private String name;private GroupEntity group;
}
创建模型对象:
由于 Realm 对象都强依赖于 Realm,它们应该直接通过 Realm 被实例化,这个是比较提倡的使用方式;也可以为该模型添加构造器,通过构造方法像普通的类一样使用,但是这里有一个要求,必须包含一个无参构造器(因为通过Realm实例化的时候需要默认无参构造器)。这里我直接使用官方文档的示例了:
realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("john@corporation.com");
realm.commitTransaction();
User user = new User("John");
user.setEmail("john@corporation.com");
三、事务
1.查询
Realm的查询是比较方便的,支持链式调用(好像应该叫函数式)并且不是必须包含在事务中。
Realm realm = Realm.getDefaultInstance();RealmResults<GroupEntity> results = realm.where(GroupEntity.class).findAll();
如上代码,获取到realm对象后就可以进行查询操作了。
接下来说个牛逼的:级联查询
接触过数据库的兄弟姐妹们都知道两张表连在一起查询的时候简直烦到死,什么左联右联;使用外键id对应的名称时得两次查询......反正是一堆苦水啊。
当你使用realm的时候,如上面提到过的两个关联的表,如果想根据groupEntity的某个字段的值来获取ContactEntity的数组,而该字段在ContactEntity中没有直接关系,就可以这样写了:
RealmResults<ContactEntity> entities = realm.where(ContactEntity.class).equalTo("group.name",name)//”当前列名.关联列名”的形式.findAll();
如果是其他的数据库,这里就需要先查到name对应的groupid,根绝groupid再来查询ContactEntity表.....Realm关联查询就是这么简单,好用到爆!
支持的查询条件:
·between()、greaterThan()、lessThan()、greaterThanOrEqualTo() 和 lessThanOrEqualTo()
·equalTo() 和 notEqualTo()
·contains()、beginsWith() 和 endsWith()
·isNull() 和 isNotNull()
·isEmpty() 和 isNotEmpty()
·or()和and()
·not()
·sort()//排序
2.写入(必须包含进事务)
写入包括增删改三个方面。
使用事务由两种方式
方式一、
realm.beginTransaction();
//写入操作
realm.commitTransaction();
//realm.cancelTransaction() //发生错误时可以取消操作
方式二、
realm.executeTransaction(new Realm.Transaction() {@Overridepublic void execute(Realm realm) {//写入操作}});
异步事务的方式就是方式二的方法名多了几个字符Asyn(OnSuccess和OnError是可选重载项)
realm.executeTransactionAsync(new Realm.Transaction() {@Overridepublic void execute(Realm bgRealm) {User user = bgRealm.createObject(User.class);user.setName("John");user.setEmail("john@corporation.com");}}, new Realm.Transaction.OnSuccess() {@Overridepublic void onSuccess() {// Transaction was a success.}}, new Realm.Transaction.OnError() {@Overridepublic void onError(Throwable error) {// Transaction failed and was automatically canceled.}});
注意:异步事务调用会返回一个 RealmAsyncTask 对象。当你退出 Activity 或者 Fragment 时可以使用该对象取消异步事务。如果你在回调函数中更新 UI,那么忘记取消异步事务可能会造成你的应用崩溃。
public void onStop () {if (transaction != null && !transaction.isCancelled()) {transaction.cancel();}}
四、版本变迁:
1.忽略变迁:
直接在配置中添加就行:
RealmConfiguration config = new RealmConfiguration.Builder(context).deleteRealmIfMigrationNeeded().build()
接下的处理方式建议放在RealmMigration的实现类中,因为匿名内部类在多版本的情况下结构上看起来会很夸张,不方便阅读。
新建类继承RealmMigration,添加默认方法的实现:
void migrate(DynamicRealm realm, long oldVersion, long newVersion);
DynamicRealm :继承自BaseRealm的动态的Realm对象,通过它来完成迁移的任务。
2.添加新表:
这个时候,数据库的结构会发生变化,所以需要一个架构级的对象来进行操作,这里需要首先获取一个RealmSchema 对象:
RealmSchema schema = realm.getSchema();
Schema可以看作是一个库级的可操作对象。
然后是对对应版本做相对处理:
if (oldVersion==2){schema.create("Contact").addField("name",String.class)//对象名称和类型.addField("id",int.class, FieldAttribute.INDEXED)//可以制定约束.addField("url",String.class).addField("pinyin",String.class).addField("firstChar",String.class);oldVersion++;
}
3.修改已有表:
if (oldVersion==3){schema.get("Contact").addField("group",String.class).addRealmObjectField("favoriteDog", schema.get("Dog"))//RealmObj数据.addRealmListField("dogs", schema.get("Dog"))//List<RealmObj>数据.renameField("url","lru")//修改列名.removeField("url");//删除列oldVersion++;
}
4.删除表:
if(oldVersion==4){schema.remove("Contact");//删除表
}