CRUD - 读取 - Java SDK
在此页面上
读取操作
您可以读回存储在Realm中的数据。 Realm SDK 的标准数据访问模式是按顺序查找、过滤和排序对象。 随着应用的增长和查询变得更加复杂,为了从Realm获得最佳性能,请围绕对Realm 读取特征的深入理解来设计应用程序的数据访问模式。
读取特征
当您围绕 Realm 中读取的以下三个关键特征设计应用的数据访问模式时,您可以确信自己正在尽可能高效地读取数据。
结果不是副本
查询的结果不是数据副本:修改查询结果将直接修改磁盘上的数据。这种内存映射还意味着结果是实时的:也就是说,它们始终反映磁盘上的当前状态。
结果出现延迟
Realm会推迟查询的执行,直到您访问权限结果。 您可以链接多个过滤和排序操作,而无需额外的工作来进程中间状态。
引用被保留
Realm 对象模型的一项优势是,Realm 会自动将对象的所有关系保留为直接引用,因此您可以通过查询结果直接遍历关系图。
直接引用或指针允许您直接通过该引用访问相关对象的属性。
当您需要直接使用对象时,其他数据库通常会将对象从数据库存储复制到应用程序内存中。由于应用程序对象包含直接引用,因此您只有一个选项:将每个直接引用所引用的对象从数据库中复制出来(如果需要),或仅复制每个对象的外键并在该对象被访问的情况下使用该键来查询此对象。如果选择将引用的对象复制到应用程序内存中,则可能会为从未访问过的对象占用大量资源;但是,如果选择仅复制外键,引用的对象查找则可能会导致应用程序变慢。
Realm 使用零拷贝活动对象绕过所有这些操作。Realm 对象访问器使用内存映射直接指向数据库存储,因此 Realm 中的对象与应用程序内存中的查询结果没有区别。因此,您可从任一查询结果遍历整个 Realm 的直接引用。
关于本页中的示例
本页上的示例使用具有两种 Realm 对象类型的项目管理应用的Realm 数据模型: Project
和Task
。 Project
具有零个或多个Tasks
。
请参阅 Project
和 Task
这两个类的模式,如下所示:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.RealmClass; import io.realm.annotations.Required; public class ProjectTask extends RealmObject { public ObjectId _id; public String name; public String assignee; public int progressMinutes; public boolean isComplete; public int priority; public String _partition; }
import org.bson.types.ObjectId; import io.realm.RealmList; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.RealmClass; import io.realm.annotations.Required; public class Project extends RealmObject { public ObjectId _id; public String name; public RealmList<ProjectTask> tasks = new RealmList<>(); }
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import org.bson.types.ObjectId open class ProjectTask( var _id: ObjectId = ObjectId(), var name: String = "", var assignee: String? = null, var progressMinutes: Int = 0, var isComplete: Boolean = false, var priority: Int = 0, var _partition: String = "" ): RealmObject()
import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import org.bson.types.ObjectId open class Project( var _id: ObjectId = ObjectId(), var name: String = "", var tasks: RealmList<ProjectTask> = RealmList(), ): RealmObject()
从 Realm 读取
Realm 读取一般包括以下步骤:
所有查询、过滤和排序操作都会返回一个结果集合。 结果集合是实时的,这意味着它们始终包含关联查询的最新结果。
重要
UI 线程上的同步读写
默认情况下,只能使用异步事务在应用程序的用户界面线程中读取或写入域。也就是说,除非您明确允许使用同步方法,否则您只能在 Android 应用程序的主线程中使用名称以单词 Async
结尾的 Realm
方法。
此限制是为了应用程序用户的利益:在 UI 线程上执行读写操作,可能导致 UI 交互无响应或速度缓慢,所以通常来说,最好以异步方式或在后台线程中处理这些操作。但是,如果应用程序需要在 UI 线程上使用同步 Realm 读取或写入,则可以通过以下 SyncConfiguration
选项明确支持使用同步方法:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); } });
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread.") } })
按主键查找特定对象
要查找具有特定主键的对象,请打开一个域并使用RealmQuery.equalTo()在主键字段中查询所需的主键。 方法:
ProjectTask task = realm.where(ProjectTask.class).equalTo("_id", PRIMARY_KEY_VALUE.get()).findFirst(); Log.v("EXAMPLE", "Fetched object by primary key: " + task);
val task = realm.where(ProjectTask::class.java) .equalTo("_id", ObjectId.get()).findFirst() Log.v("EXAMPLE", "Fetched object by primary key: $task")
查询给定类型的所有对象
任何读取的第一步都是获取域中特定类型的所有对象。 使用此结果集合,您可以对类型或过滤的所有实例进行操作并进行排序以优化结果。
要访问权限ProjectTask
和Project
的所有实例,请使用where()方法指定一个类:
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); RealmQuery<Project> projectsQuery = realm.where(Project.class);
val tasksQuery = realm.where(ProjectTask::class.java) val projectsQuery = realm.where(Project::class.java)
根据对象属性筛选查询
筛选器根据一个或多个对象属性的值选择结果子集。 Realm 提供了一个功能齐全的查询引擎,您可以使用它来定义筛选器。 最常见的用例是查找特定属性与特定值匹配的对象。 此外,您还可以比较字符串、聚合数字集合以及使用逻辑运算符来构建复杂的查询。
在以下示例中,我们使用查询引擎的比较运算符执行以下操作:
通过将
priority
属性值与阈值数字进行比较来查找高优先级任务,而高于该阈值的优先级可视为高优先级。通过查看
progressMinutes
属性是否在特定范围内来查找刚刚启动或短时间运行的任务。通过查找
assignee
属性等于 null 的任务来查找未分配的任务。通过查看
assignee
属性是否在名称列表中来查找分配给团队成员 Ali 或 Jamie 的任务。
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); Log.i("EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan("priority", 5).count()); Log.i("EXAMPLE", "Just-started or short tasks: " + tasksQuery.between("progressMinutes", 1, 10).count()); Log.i("EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count()); Log.i("EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.in("assignee", new String[]{"Ali", "Jamie"}).count());
val tasksQuery = realm.where(ProjectTask::class.java) Log.i( "EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan( "priority", 5 ).count() ) Log.i( "EXAMPLE", "Just-started or short tasks: " + tasksQuery.between( "progressMinutes", 1, 10 ).count() ) Log.i( "EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count() ) Log.i( "EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.`in`( "assignee", arrayOf( "Ali", "Jamie" ) ).count() )
对查询结果进行排序
排序操作允许您配置 Realm 返回查询对象的顺序。您可以根据结果集合中对象的一个或多个属性进行排序。
仅当结果已进行排序时,Realm 才能保证结果顺序一致。
以下代码按名称倒序排列项目(即 “降序”)。
RealmQuery<Project> projectsQuery = realm.where(Project.class); RealmResults<Project> results = projectsQuery.sort("name", Sort.DESCENDING).findAll();
val projectsQuery = realm.where(Project::class.java) val results = projectsQuery.sort("name", Sort.DESCENDING).findAll()
查询关系
考虑类Human
和Cat
之间的以下关系。 这种安排允许每个人拥有一只猫:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Human extends RealmObject { private ObjectId _id = new ObjectId(); private String name; private Cat cat; public Human(String name) { this.name = name; } public Human() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public ObjectId get_id() { return _id; } }
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; import io.realm.annotations.PrimaryKey; public class Cat extends RealmObject { private ObjectId _id = new ObjectId(); private String name = null; private final RealmResults<Human> owner = null; public Cat(String name) { this.name = name; } public Cat() { } public ObjectId get_id() { return _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public RealmResults<Human> getOwner() { return owner; } }
要查询此关系,请在查询中使用点表示法来访问权限链接对象的任何属性:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); realm.executeTransaction(transactionRealm -> { Human owner = transactionRealm.where(Human.class).equalTo("cat.name", "bucky").findFirst(); Cat cat = owner.getCat(); Log.v("EXAMPLE", "Queried for humans with cats named 'bucky'. Found " + owner.getName() + ", who owns " + cat.getName()); }); realm.close(); } });
考虑类Person
和Dog
之间的以下关系。 这种安排允许每个人拥有一只狗:
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Person(var name : String? = null) : RealmObject() { var _id : ObjectId = ObjectId() var dog: Dog? = null }
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Dog(var name : String? = null): RealmObject() { var _id : ObjectId = ObjectId() val owner: RealmResults<Person>? = null }
要查询此关系,请在查询中使用点表示法来访问权限链接对象的任何属性:
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ) realm.executeTransaction { transactionRealm -> val owner = transactionRealm.where<Person>().equalTo("dog.name", "henry").findFirst() val dog = owner?.dog Log.v("EXAMPLE", "Queried for people with dogs named 'henry'. Found $owner, owner of $dog") } realm.close() } })
查询反向关系
考虑类Cat
和Human
之间的以下关系。 在此示例中,所有猫都链接到其人类(或多个人类,如果多个人类对象引用同一只猫)。 Realm会根据您为@LinkingObjects
注解提供的字段名称,为您计算每只猫的所有者:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; import io.realm.annotations.PrimaryKey; public class Cat extends RealmObject { private ObjectId _id = new ObjectId(); private String name = null; private final RealmResults<Human> owner = null; public Cat(String name) { this.name = name; } public Cat() { } public ObjectId get_id() { return _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public RealmResults<Human> getOwner() { return owner; } }
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Human extends RealmObject { private ObjectId _id = new ObjectId(); private String name; private Cat cat; public Human(String name) { this.name = name; } public Human() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public ObjectId get_id() { return _id; } }
要查询此关系,请在查询中使用点表示法来访问权限链接对象的任何属性:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); realm.executeTransaction(transactionRealm -> { Cat cat = transactionRealm.where(Cat.class) .equalTo("owner.name", "steven").findFirst(); Human owner = cat.getOwner().first(); Log.v("EXAMPLE", "Queried for cats with owners named 'steven'. Found " + cat.getName() + ", owned by " + owner.getName()); }); realm.close(); } });
考虑类Dog
和Person
之间的以下关系。 在此示例中,所有狗都链接到其所有者(或多个所有者,如果多个人员对象引用同一只狗)。 Realm 会根据您为@LinkingObjects
注解提供的字段名称,为您计算每只狗的主人:
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Dog(var name : String? = null): RealmObject() { var _id : ObjectId = ObjectId() val owner: RealmResults<Person>? = null }
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Person(var name : String? = null) : RealmObject() { var _id : ObjectId = ObjectId() var dog: Dog? = null }
要查询此关系,请在查询中使用点表示法来访问权限链接对象的任何属性:
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ) realm.executeTransaction { transactionRealm -> val dog = transactionRealm.where<Dog>() .equalTo("owner.name", "dwayne").findFirst() val owner = dog?.owner?.first() Log.v("EXAMPLE", "Queried for dogs with owners named 'dwayne'. Found $dog, owned by $owner") } realm.close() } })
聚合数据
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); /* Aggregate operators do not support dot-notation, so you cannot directly operate on a property of all of the objects in a collection property. You can operate on a numeric property of the top-level object, however: */ Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"));
val tasksQuery = realm.where(ProjectTask::class.java) /* Aggregate operators do not support dot-notation, so you cannot directly operate on a property of all of the objects in a collection property. You can operate on a numeric property of the top-level object, however: */Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"))