关系 — Kotlin SDK
本页介绍如何定义数据模型中对象之间的关系。 要学习;了解Realm对象以及如何定义它们,请参阅定义Realm 对象模型- Kotlin SDK。
与关系数据库不同,Realm 不使用桥接表或显式联接来定义关系。 相反,Realm 通过嵌入式对象或对其他 Realm 对象的引用属性来处理关系。 您可以直接读取和写入这些属性。 这使得查询关系与查询任何其他属性一样高效。
关系类型
Realm 对象之间有两种主要的关系类型:
对一关系
对多关系
Realm本身并不限制同一域中其他对象的对象引用。 这意味着Realm关系是隐式的“多对一”或“多对多”。 将关系限制为“一对一/一对多”而不是“多对一/多对多”的唯一方法是使用嵌入式对象,它是只有一个父对象的嵌套对象。
定义关系
您可以通过定义引用另一个 Realm 对象的对象属性来定义对象模式中的关系。 了解有关使用Realm 对象作为属性的更多信息。
您可以使用以下类型定义关系:
RealmObject
RealmList <? extends RealmObject>
RealmSet <? extends RealmObject>
您还可以将一个Realm 对象直接嵌入另一个 Realm 对象,以创建具有EmbeddedRealmObject
类型的嵌套数据结构。 但是,嵌入式对象有其他限制。 有关更多信息,请参阅定义嵌入式对象部分。
定义对一关系属性
关系关系将一个属性映射到RealmObject
对象类型的单个实例。 没有什么可以阻止多个父对象实例引用同一个子实例。 如果要实施严格的一对一关系,请改用嵌入式对象。
注意
将对一关系字段设置为null
会删除对象之间的连接,但Realm不会删除引用的对象。 如果要在删除对象的对象,请改用嵌入式对象。
要定义对象之间的对一关系,请定义一个可选对象属性,其类型为数据模型中定义的RealmObject
对象。 可以是不同的 Realm 对象类型,也可以是相同的 Realm 对象类型:
// Relationships of Realm objects must be of RealmObject type class Frog : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" var age: Int = 0 // Property of RealmObject type (MUST be null) var favoritePond: Pond? = null var bestFriend: Frog? = null }
定义对多关系属性
对多关系将一个属性映射到RealmObject
对象类型的零个或多个实例。 没有什么可以阻止多个父对象实例引用同一个子实例。 如果要强制执行严格的一对多关系,请改用嵌入式对象。
在Realm中,对多关系是Realm对象的集合( RealmList或RealmSet )。 有关在对象模型中定义集合的更多信息,请参阅定义集合属性。
要定义对象之间的对多关系,请定义一个类型为RealmList<E>
或RealmSet<E>
的对象属性,其中<E>
是数据模型中定义的RealmObject
对象类型。 可以是不同的Realm 对象类型,也可以是相同的Realm 对象类型:
// Relationships of RealmList<E> or RealmSet<E> must be of RealmObject type class Forest : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // Set of RealmObject type (CANNOT be null) var frogsThatLiveHere: RealmSet<Frog> = realmSetOf() // List of RealmObject type (CANNOT be null) var nearbyPonds: RealmList<Pond> = realmListOf() }
定义反向关系
反向关系是RealmObject
子对象与引用该对象的任何其他父对象之间的自动反向链接关系。 反向关系可以链接回多对一或多对多关系中的子对象。 如果要实施严格的一对一或一对多反向关系,请改用嵌入式对象。
关系定义是单向的,因此您必须在对象模型中将属性显式定义为反向关系。 示例,对多关系“用户有许多帖子”不会自动创建反向关系“帖子属于用户”。 但是,您可以在帖子上添加一个指向帖子所有者的用户属性。 这样,您就可以查询从帖子到用户的反向关系,而不是运行单独的查询来查找帖子所属的用户。 由于关系是多对一或多对多,因此遵循反向关系可能会得到零个、一个或多个对象。
注意
每当在指定关系中添加或删除对象时,Realm 都会自动更新隐式关系。 您无法手动在反向链接集合中添加或删除项目。
要定义对象之间的反向关系,首先在父对象中定义一个集合属性,其类型为RealmList<E>
、 RealmSet<E>
或RealmDictionary<E>
,其中<E>
是数据模型中定义的RealmObject
对象类型。 可以是不同的 Realm 对象类型,也可以是相同的 Realm 对象类型:
// Parent object must have RealmList<E>, RealmSet<E>, or // RealmDictionary<K,V> property of child type class User : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // List of child RealmObject type (CANNOT be nullable) var posts: RealmList<Post> = realmListOf() // Set of child RealmObject type (CANNOT be nullable) var favoritePosts: RealmSet<Post> = realmSetOf() // Dictionary of child RealmObject type (value MUST be nullable) var postByYear: RealmDictionary<Post?> = realmDictionaryOf() }
然后,在RealmResults<E>
的子对象中定义一个不可变的反向链接属性,其中<E>
是父对象类型:
// Backlink of RealmObject must be RealmResults<E> of parent object type class Post : RealmObject { var title: String = "" var date: RealmInstant = RealmInstant.now() // Backlink to parent RealmObject type (CANNOT be null & MUST be val) val user: RealmResults<User> by backlinks(User::posts) }
定义嵌入式对象
嵌入式对象是一种特殊类型的Realm 对象,可用于在单个特定父对象内嵌套数据。 嵌入式对象可以是一对一、一对多或与前面部分中描述的关系类似的反向关系,但该关系仅限于单个父对象和EmbeddedRealmObject
类型。
由于嵌入式对象不能作为独立的Realm对象存在,因此它们还需要考虑其他约束:
嵌入式对象由其父对象严格拥有所有权。 不能在父对象之间共享嵌入式对象。
嵌入式对象会继承其父对象的生命周期。 示例,删除父对象也会删除嵌入式对象。
当存在明确的包含或所有权关系时,嵌入式对象非常有用。 示例, Address
对象可以嵌入在User
对象中,因为它仅在用户上下文中的应用程序中有意义。
提示
嵌入式对象类型可重用、可组合
您可以在多个父对象类型以及其他嵌入式对象类型中使用相同的嵌入式对象对象类型。
一对一关系
要定义与其父对象具有一对一关系的嵌入式对象,请定义一个对象属性,其类型为已在数据模型中定义的EmbeddedRealmObject
:
// To-one embedded relationships must be of EmbeddedRealmObject type class Contact : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // Property of EmbeddedRealmObject type (MUST be null) var address: EmbeddedAddress? = null } class EmbeddedAddress : EmbeddedRealmObject { var propertyOwner: Contact? = null var street: String? = "" // Embed another EmbeddedRealmObject type var country: EmbeddedCountry? = null } class EmbeddedCountry : EmbeddedRealmObject { var name: String = "" }
一对多关系
要定义与其父对象具有一对多嵌入式关系的嵌入式对象,请定义一个类型为RealmList<E>
的对象属性,其中<E>
是数据模型中定义的EmbeddedRealmObject
对象类型:
// To-many embedded relationships must be a RealmList<E> or // RealmDictionary<K, V> property of EmbeddedRealmObject type class Business : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // List of EmbeddedRealmObject type (CANNOT be null) var addresses: RealmList<EmbeddedAddress> = realmListOf() // Dictionary of EmbeddedRealmObject type (value MUST be nullable) var addressByYear: RealmDictionary<EmbeddedAddress?> = realmDictionaryOf() }
您不能定义具有RealmSet<E>
类型的嵌入式对象,因为RealmSet<E>
不支持嵌入式对象。
反向关系
要定义与其父对象具有反向关系的嵌入式对象,请先在类型为RealmList<E>
或RealmDictionary<E>
的父对象中定义集合属性,其中<E>
是数据模型中定义的EmbeddedRealmObject
对象类型:
// Parent object must have RealmList<E> or RealmDictionary<K, V> // property of child EmbeddedRealmObject type class User : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" // List of child EmbeddedRealmObject type (CANNOT be nullable) var posts: RealmList<Post> = realmListOf() // Dictionary of child EmbeddedRealmObject type (value MUST be nullable) var postByYear: RealmDictionary<Post?> = realmDictionaryOf() }
您不能定义具有RealmSet<E>
类型的嵌入式对象,因为RealmSet<E>
不支持嵌入式对象。
然后,在类型为父对象类型的子对象中定义一个不可变的反向链接属性:
// Backlink of EmbeddedRealmObject must be parent object type class Post : EmbeddedRealmObject { var title: String = "" var date: RealmInstant = RealmInstant.now() // Backlink to parent RealmObject type (CANNOT be null & MUST be val) val user: User by backlinks(User::posts) }