跳转至

ManagedObject 的序列化和反序列化

在本指南中,您将学习如何从HTTP请求体中读取 "ManagedObject"并写入HTTP响应体。

基本转换

ManagedObject<T>可以转换为Map<String, dynamic>对象,也可以从Map<String, dynamic>对象中转换。每个键都是对象中的一个属性的名称。要将一个ManagedObject解码为Map,请调用它的read方法

final object = MyManagedObject();
object.read({
  "key": "value"
});

// object.key == "value"

当输入数据无效时,会抛出验证异常(状态代码:400):如果一个键没有相应的属性,值的类型与预期的类型不匹配,或者违反了管理对象的某些约束。

筛选器可以应用于被读对象的键值。过滤器可以忽略键,要求键,或者在存在键的情况下抛出一个异常。下面是一个例子,在这个例子中,由于'id'是必需的,但没有提供,所以读取会抛出一个异常。

object.read({
  "key": "value"
}, require: ["id"]);

ManagedObjects继承Serializable

read方法和它的过滤器继承自Serializable这里将详细讨论。被管理的对象,就像可序列化对象一样,可以被绑定到操作方法参数中。

管理的对象有一个默认键的列表,可以作为基础过滤器集。

object.read({}, require: object.entity.defaultProperties);

要将一个被管理对象序列化为map,请使用实例方法asMap:

final object = MyManagedObject();
Map<String, dynamic> map = object.asMap();

如果对象上的属性没有被设置,那么它将不会被写到map中。

等同于管理对象的“ Map”的值始终是原始值,可以将其编码为JSON,通过isolate对象进行发送等。以下显示了序列化格式的表:

Dart Type Serialized Type
int number (int)
double number (double)
String string (String)
DateTime ISO 8601 Timestamp (String)
bool boolean (bool)
Document map or list (Map<String, dynamic> or List<dynamic>)
Any enum string (String)
Belongs-To or Has-One Relationship map (Map<String, dynamic>)
Has-Many Relationship list of maps (List<Map<String, dynamic>>)

Null 值的行为

一个被管理对象的属性可以为null,原因有两个:值实际上为null,或者值不可用。例如,当你创建一个新的被管理对象的实例时,它的值没有一个是可用的(该对象是空的)。当将一个对象编码成映射时,只包含可用的值,而省略了任何不可用属性的键。

final myObject = MyManagedObject(); // empty object
myObject.asMap() == {}; // true

myObject.id = 1;
myObject.asMap() == {
  "id": 1
}; // true

仅当属性值确实为null时,托管对象的asMap中的值才为null:

myObject.id = null;
myObject.asMap() == {
  "id": null
}; // true

通过访问器设置属性值,使用read或从查询返回对象时,属性值才可用。

瞬态属性的行为

默认情况下,对象的asMap()中不包含瞬态属性(在托管对象子类中声明的属性,而不是表定义中声明的属性)。 Serialize注解允许在此映射中包含一个瞬态属性。

class Employee extends ManagedObject<_Employee> implements _Employee {
  int a; // NOT included in asMap, NOT read in read

  @Serialize()
  int b; // included in asMap, read in read

  @Serialize(input: true, output: false)
  int c; // NOT included in asMap, read in read

  @Serialize(input: false, output: true)
  int d; // included in asMap, NOT read in read
}

class _Employee {
  @primaryKey
  int id;
}

可能存在单独的getter和setter而不是属性。 有了这个注解,getter被添加到asMap中,并且setter将被输入到read中。

class User extends ManagedObject<_User> implements _User {
  @Serialize()
  set transientValue(String s) {
    ...
  }

  @Serialize()
  String get transientValue => ...;
}

如果瞬态属性的键值为null,则不会在asMap()中出现。

关系属性的行为

对托管对象进行编码时,关系属性被表示为map(对于属于或具有has-one关系)或map列表(对于具有has-many关系)。 属性的可用性规则同样适用于关系属性。 下面显示了一个示例map,该map映射了具有适当命名的关系属性的托管对象:

{
  "id": 1,
  "belongsTo": {
    "id": 1
  },
  "hasOne": {
    "id": 2,
    "name": "Fred"
  },
  "hasMany": [
    {"id": 3, "name": "Bob"},
    {"id": 4, "name": "Joe"},
  ]
}

belongs-to关系永远是一个映射关系。这对于经常创建或更新对象的所属关系的客户端应用程序很重要。 例如,希望创建一个名为Timmy的子对象且其父对象的id == 1的客户端将发送以下JSON:

{
  "name": "Timmy",
  "parent": {
    "id": 1
  }
}

这与某些可以使这种结构扁平化的框架不同,例如:

{
  "name": "Timmy",
  "parent_id": 1
}