13. ORM Part 2: 定义对象

游戏工程师在SourceTree的 src/object_model/ 目录下使用JSON文件定义对象。 这时指定对象名和属性方式如下。

{
  "ObjectName": {
    "AttributeName": "Type Flags",
    "AttributeName": "Type Flags",
    ...
  },
  "ObjectName": {
    "AttributeName": "Type Flags",
    "AttributeName": "Type Flags",
    ...
  },
  ...
}

在这儿的 ObjectName 会成为 Character 或者 Weapon 等 模型的名称。 并且,AttributeName 会成像 Title 或者 Level 一样属性的名称。

Important

Object, Attribute 的名称尽量输入为 Camel 的形式。

要不然,自动产生的Class或者Method名称不会漂亮。

  • (不好的例子)输入 my_character 的时候自动产生的参数名称: Getmy_character()

  • (不好的例子)输入 myCharacter 自动产生的参数名称: GetmyCharacter()

  • (好的例子)输入 MyCharacter 自动产生的参数名称: GetMyCharacter()

Tip

使用JSON的时候不能使用 // ... 或者 /* ... */ 形式的注释, iFun Engine的ORM定义文件可使用这样的注释。

开发阶段中,这样方式在模型或者档案上留标注的时候会有用。

13.1. Attribute 的 Type

Attribute的类型的话,iFun Engine提供的基本类型或者其他模型名称都可以使用,并且Array或者Map形式也可以使用。

13.1.1. 基本类型

  • Bool: 意味着真/假。

  • Integer: 意味着整数。

  • Double: 意味着实数。

  • String(n): 意味着n个字符串。

    Important

    String(n) 的话不是Byte单位,而是数国际码单位。 有需要的话,可以使用 util::GetUtf8Length() 确认字符单位数。

    如果保存n字符以上字符串的话,切断n字符以后部分后保存。 如果需要切断明确的特定字符以下的话,使用 util::TruncateUtf8() 参数即可。

    Important

    String 不再支持,一定使用 String(n)

    如果已有的项目中使用 String 的话,因为 StringString(n) 不能并用,所以需要要么继续使用 String 要么之前使用的东西换成 String(n)

 // 14个文字, 36 Byte字符串
 std::string s = "松鼠像坐旧筛筐";
 BOOST_ASSERT(14 == util::GetUtf8Length(s));
 BOOST_ASSERT(36 == s.size());

 // 切断从头起三个字
 std::string t = util::TruncateUtf8(s, 3);
 BOOST_ASSERT("松鼠" == t);

13.1.2. 对象类型

除了基本类型之外,还可以把其他模型的名称使用为类型。这情况下该属性有了对象类型。 不需要一定在前边宣布该模型。

下面例子中 MyChracter 属性成为 Chracter 的对象类型。

"User": {
  "MyCharacter": "Chracter"
},
"Character": {
  "Hp": "Integer",
  "Mp": "Integer"
}

13.1.3. 数组 (Array)

类型后面添加 [] 的话成为数组形式。

举个例子 Integer[], String(12)[], Character[] 意味着基本类型的各个整数数组,长为12个的字符串数组,而且使用者指定的 Character 的类型。

数组类型的属性产生C++/C#类的时候也支持像 InsertAt() 或者 EraseAt() 一样使用索引的数组工作。

Important

数组时候中间删除已有的内容或者添加的话,因数组在整列而速度会变慢。 具体内容请您参考 Using Array and Map

13.1.4. 地图 (Map)

指定为 <KeyType, ValueType> 的形式。

KeyType 只能用基本类型, 在 ValueType 不仅用基本类型还可以用对象类型。

举个例子,<Integer, String(4)> 意味着以整数为Key和4个字符串为Value的地图类型,<String(64), Item> 意味着64个字符串为Key和Item为Value的地图类型。

13.2. Attribute 的 Flag

13.2.1. Key

该属性做成key。 Key不许重复值,一旦决定值,不会变更。 使用Key可以调用 Object。 在MySQL上设置为 Non-Clustered Index 以及 Unique Constraint

下面的例子是 Character 的 Name 指定为 Key的情况。

"Character": {
    "Name": "String Key"
}

13.2.2. 복합키(Composite Key)

여러 속성을 하나의 복합키(Composite Key)로 지정합니다. 복합키는 키와 동일한 특징을 가지고 있으며 두 개 이상의 속성을 키로 등록할 때 사용할 수 있습니다.

Important

한 오브젝트에 복합키와 키를 동시에 사용할 수 없습니다.

아래 예제는 Map 오브젝트의 X와 Y 속성을 복합키로 지정한 경우입니다.

    "MAP": {
        "X": "String(10)",
        "Y": "String(10)",
        ...
        "COMPOSITE_KEY":[
          "X", "Y"
        ]
    }

13.2.3. Foreign

属性的类型使用为其他模型的名称的时候,可以指定 Foreign 。 这样方式从数据库加载队形的时候,没有自动加载该属性的对象,而是只加载对象的ID值后需要的时候才加载该属性的对象。

举个例子, 假设有下面的 Character 和 Weapon 模型

"Character": {
    "MyWeapon": "Weapon"
},
"Weapon": {
    "Durability: "Integer"
}

这种情况,从数据库加载 Character 的话,把 Weapon 类型的 MyWeapon 也一起加载.

有明确的所有关系的话这样自动加载方式很方便。 但是,共有的对象和属于别人的对象的话这样自动加载方式有可能会出现问题。 这时,可以指定 Foreign 这意味着 参考

"Character": {
    "MyWeapon": "Weapon Foreign"
},
"Weapon": {
    "Durability: "Integer"
}

如上指定 Foreign 的话,虽然加载 Character 但是,不自动地加载 MyWeapon 。 ㅇ但是,先保存 MyWeapon 的对象ID后, 从数据库加载 MyWeapon 的时候会使用。

Tip

在数组或者地图的情况下像 Item[] Foreign 或者 <Integer, Item> Foreign 一样数组和地图定义后面写 Foreign

13.3. 模型定义例子

下面的例子定义 CharacterItem 的对象。 以后,本章和跟ORM相关的章都定义对象模型。

src/object_model/example.json

{
  "User": {
    "Id": "String(16) KEY",
    "MyCharacter": "Character"
  },

  "Character": {
    "Name": "String(16) Key",
    "Exp": "Integer",
    "Level": "Integer",
    "Hp": "Integer",
    "Mp": "Integer",

    "Inventory": "Item[]",

    "QuickSlot": "<Integer, Item>",
    "EquippedItem": "<String(9), Item>"
  },

  "Item": {
    "Type": "String(16)"
  }
}

约20行的渐变的Object Modeling工作,User, Character, Item 的对象都能实现。 那现在使用按照这JSON自动产生的Class的话, iFun Engine能自动处理像数据库处理,Cache实现,实现扩展处理,多线程处理等复杂的工作。