对象模型 - .NET SDK
创建对象模型
Realm 类是定义 Realm 模式的普通 C# 类。
重要
继承
所有Realm对象都继承自 IRealmObject 、 IEmbeddedObject或IAsymmetricObject接口,并且必须声明为 partial
类。
在早于10.18.0的 .NET SDK 版本中, 派生自RealmObject 、 EmbeddedObject或AsymmetricObject基类的对象。 这种 Realm 模型定义方法仍然受支持,但不包括可空性注解等新功能。 在未来的 SDK 版本中,基类将被弃用。 您编写的任何新类都应使用接口,并应考虑迁移现有类。
注意
类名不得超过 57 个 UTF-8 字符。
对象模式
对象模式是定义 Realm 对象属性和关系的配置对象。Realm 客户端应用程序使用“Object Schema”(对象模式),以相应的语言通过原生类实现来定义对象模式。
对象模式指定对对象属性的约束,例如每个属性的数据类型以及是否需要属性。模式还可以定义 Realm 中对象类型之间的关系。
每个应用程序都有一个App Services Schema,由该应用程序可能包含 Realm 的每种类型对象的对象模式列表组成。Realm 保证所有 Realm 对象都符合对象类型的模式,并在创建、修改或删除对象时对其进行验证。
属性注解
模式属性是RealmObject
上的标准 C# 属性。您可以使用多个属性注解来更精细地定义 Realm 如何处理特定属性。
主键
主键是一个唯一标识对象的属性。您可以使用以下任何类型(或其可为 null 的对应项)创建主键:
ObjectId
UUID
string
char
byte
short
int
long
您可以在对象类型的单个属性上定义主键,作为对象模式的一部分。Realm 会自动为主键属性建立索引,因此您可以根据主键高效地读取和修改对象。
如果某个对象类型具有主键,则该类型的所有对象都必须包含主键属性,并且在 Realm 中相同类型的对象中,该主键属性具有唯一值。
注意
一旦将某个属性指定为主键,就无法对其进行更改。
以下示例演示了如何在对象模式中指定主键:
public partial class Dog : IRealmObject { [ ] public string Name { get; set; } public int Age { get; set; } public Person? Owner { get; set; } }
索引
索引显著缩短了 Realm 中的查询时间。如果没有索引,Realm 会扫描集合中的每份文档,从而选择与给定查询匹配的文档。但是,如果查询存在适用的索引,Realm 将使用该索引来限制必须检查的文档数量。
您可以为以下类型的属性建立索引:
bool
byte
short
int
long
DateTimeOffset
char
string
ObjectId
UUID
注意
添加索引可以加快某些查询的速度,但代价是写入速度稍慢,并增加存储和内存开销。索引需要 Realm 文件的空间,因此为属性添加索引会增加 Realm 文件消耗的磁盘空间。每个索引条目至少有 12 个字节。
要为属性建立索引,请使用Indexed属性。 通过Indexed
属性,您可以使用IndexType枚举指定属性的索引类型。 在以下示例中,我们在Name
属性上设置了默认(“常规”)索引:
public partial class Person : IRealmObject { [ ] public string Name { get; set; } [ ] public string Biography { get; set; } }
注意
创建索引时,您是在本地 Realm 而不是在 Atlas 集合上创建索引。 如果您需要直接查询 Atlas 集合并希望提高性能,请参阅创建、查看、删除和隐藏索引。
全文搜索索引
除了标准索引外,Realm 还支持对 string
属性创建 Atlas 全文搜索索引。虽然无论是否使用标准索引都可以查询字符串字段,但 FTS 索引支持搜索多个词汇和短语并排除其他。
有关查询全文索引的详情,请参阅全文搜索 (LINQ) 和全文搜索 (RQL)。
要为 FTS 属性建立索引,请将Indexed属性与IndexType.FullText枚举一起使用。 在以下示例中,我们在Biography
属性上建立了FullText
索引:
public partial class Person : IRealmObject { [ ] public string Name { get; set; } [ ] public string Biography { get; set; } }
默认字段值
您可以使用内置语言功能为属性指定默认值。在 C# 中,您可以在属性声明中为基元指定默认值。您不能对集合设置默认值,除非将其设置为 null!
。即使将集合设置为 null!
,集合也始终会在首次访问时初始化,因此永远不会为 null。
public partial class Person : IRealmObject { public string Name { get; set; } = "foo"; public IList<PhoneNumber> PhoneNumbers { get; } = null!; }
忽略属性
如果您不想将模型中的某个属性保存到 Realm,则可以忽略该属性。如果属性不是自动实现的或没有 setter,则默认情况下将忽略该属性。
使用 Ignore 属性,忽略 Realm 对象模型中的属性:
// Rather than store an Image in Realm, // store the path to the Image... public string ThumbnailPath { get; set; } // ...and the Image itself can be // in-memory when the app is running: [ ]public Image? Thumbnail { get; set; }
为属性重命名
默认情况下,Realm 在内部使用模型类中定义的名称来表示属性。在某些情况下,您可能想要更改此行为:
要便于在具有不同命名约定的多个平台上工作。
在不强制迁移的情况下更改 .NET 中的属性名称。
选择与模型类中使用的名称不同的内部名称,会产生以下影响:
在创建类和属性时,迁移必须使用内部名称。
模式错误报告将使用内部名称。
使用[MapTo]属性重命名属性:
public partial class Person : IRealmObject { [ ] public string Name { get; set; } }
重命名类
默认情况下,Realm 在内部使用模型类中定义的名称来表示类。在某些情况下,您可能想要更改此行为:
支持在不同命名空间中具有相同简单名称的多个模型类。
要便于在具有不同命名约定的多个平台上工作。
要使用长度大于 Realm 执行的 57 个字符限制的类名。
更改 .NET 中的类名称而不强制迁移。
使用[MapTo]属性重命名类:
[ ]public partial class Person : IRealmObject { public string Name { get; set; } }
自定义 Setter
Realm 不会使用自定义 setter 存储属性。 若要使用自定义 setter,请将属性值存储在私有属性中,然后使用自定义 setter 将该值映射到公共属性。 Realm 将存储私有属性,而您则通过公共属性修改其值。 在以下代码中,私有email
属性存储在 Realm 中,但提供验证的公共Email
属性不会保留:
// This property will be stored in the Realm private string email { get; set; } // Custom validation of the email property. // This property is *not* stored in Realm. public string Email { get { return email; } set { if (!value.Contains("@")) throw new Exception("Invalid email address"); email = value; } }
定义非结构化数据
12.2.0版本新增。
从 SDK 版本12.2.0开始, 您可以在RealmValue
属性中存储混合数据的集合。 您可以使用此功能对复杂的数据结构(例如JSON或MongoDB文档)进行建模,而无需定义严格的数据模型。
非结构化数据是指不容易符合预期模式的数据,因此对单个数据类进行建模很困难或不切实际。 示例,您的应用可能具有高度可变的数据或动态数据,其结构在运行时未知。
将集合存储在混合属性中可在不牺牲功能的情况下提供灵活性,包括使用Device Sync时的性能同步。 您可以像使用非混合集合一样使用它们:
您最多可以嵌套100级混合集合。
您可以对混合集合的React进行查询和响应。
您可以查找并更新单个混合集合元素。
但是,与使用结构化模式或将JSON blob 序列化为单个string属性相比,在混合集合中存储数据的性能较低。
要对应用中的非结构化数据进行建模,请在模式中将相应属性定义为RealmValue类型。 然后,您可以设立这些RealmValue
属性设置为RealmValue
元素的列表或字典。 请注意, RealmValue
不能表示设立或嵌入式对象。
提示
当类型未知但每个值都有唯一标识符时,请使用混合数据类型的映射。
当类型未知但对象的顺序有意义时,请使用混合数据类型的列表。
从 Realm 模式中省略类
默认情况下,您的应用程序的 Realm 模式包括实现IRealmObject
或IEmbeddedObject
的所有类。如果您只想在 Realm 模式中包含这些类的子集,则可以更新配置以包含所需的特定类:
// Declare your schema partial class LoneClass : IRealmObject { public string Name { get; set; } } class AnotherClass { private void SetUpMyRealmConfig() { // Define your config with a single class var config = new RealmConfiguration("RealmWithOneClass.realm"); config.Schema = new[] { typeof(LoneClass) }; // Or, specify multiple classes to use in the Realm config.Schema = new[] { typeof(Dog), typeof(Cat) }; } }
必要属性和可选属性
在C#中,值类型(例如int
和bool
)是隐式不可为 null 的。但是,可以使用问号 (?
) 表示法将它们设为可选。
从 C# 8.0 开始,引入了可空引用类型。如果您的项目使用的是 C# 8.0 或更高版本,您还可以使用 ?
将引用类型(如 string
和 byte[]
)声明为可空。
注意
从 .NET 6.0开始,新项目默认启用可空上下文。 对于较旧的项目,您可以手动启用它。 有关详细信息,请参阅 https://learn.microsoft.com/en-us/dotnet/csharp/ language-reference/builtin-types/nullable-reference-types#setting-the-nullable-context。
Realm.NET SDK 完全支持可空感知的上下文,并使用可空性来确定属性是必要还是可选属性。SDK 有以下规则:
如果您不将值类型和引用类型属性指定为可为 null,则 Realm 假定这些属性均为必填。如果您使用
?
将其指定为可为 null,则 Realm 会将其视为可选。必须将 Realm 对象类型的属性声明为可为 null。
您不能将集合(列表、集合、反向链接和字典)声明为可为 null,但根据以下规则,它们的参数可为 null:
对于所有类型的集合,如果参数是基元(值类型或引用类型),则它们可以为必填或可以为 null。
对于列表、集合和反向链接,如果参数是 Realm 对象,则它们不能为 null。
对于值类型为 Realm 对象的字典,必须将值类型参数声明为可为 null。
以下代码片段演示了这些规则:
public partial class Person : IRealmObject { /* Reference Types */ public string NonNullableName { get; set; } public string? NullableName { get; set; } public byte[] NonNullableArray { get; set; } public byte[]? NullableArray { get; set; } /* Value Types */ public int NonNullableInt { get; set; } public int? NullableInt { get; set; } /* Realm Objects */ public Dog? NullableDog { get; set; } // public Dog NonNullableDog { get; set; } // Compile-time error /* Collections of Primitives */ public IList<int> IntListWithNonNullableValues { get; } public IList<int?> IntListWithNullableValues { get; } // public IList<int>? NullableListOfInts { get; } // Compile-time error /* Collections of Realm Objects */ public IList<Dog> ListOfNonNullableObjects { get; } // public IList<Dog>? NullableListOfObjects { get; } // Compile-time error // public IList<Dog?> ListOfNullableObjects { get; } // Compile-time error public ISet<Dog> SetOfNonNullableObjects { get; } // public ISet<Dog>? NullableSetOfObjects { get; } // Compile-time error // public ISet<Dog?> SetOfNullableObjects { get; } // Compile-time error public IDictionary<string, Dog?> DictionaryOfNullableObjects { get; } // public IDictionary<string, Dog> DictionaryOfNonNullableObjects { get; } // Compile-time error // public IDictionary<string, Dog>? NullableDictionaryOfObjects { get; } // Compile-time error [ ] public IQueryable<Dog> MyDogs { get; } // [Backlink(nameof(Dog.People))] // public IQueryable<Dog?> MyDogs { get; } // Compile-time error }
注意
如果您使用的是较旧的模式类型定义(您的类派生自RealmObject
基类),或者您没有启用可空性,则需要对任何必需的string
和byte[]
使用[Required]属性。属性。
忽略无效性
您可能希望更灵活地定义 Realm 对象中属性的可空性。 您可以通过在realm.ignore_objects_nullability = true
全局配置文件 中设置 来实现此目的。
如果您启用 realm.ignore_objects_nullability
,则 Realm 对象属性(包括 Realm 对象集合)上的可空性注释将被忽略。