4.4 实体继承
与类一样,实体也可以继承自父实体。这个功能有助于简化数据模型。子实体会自动继承父实体的各种属性。在底层的SQLite存储区里,“父-子”体系中的实体都放在同一张数据表里。
Grocery Dude里面的货品有可能位于两个地方,一个是商店,一个是家中,而我们的范例程序就要围绕这一特性而展开。既然货品有可能出现在“商店”和“家”这两种位置,那么就可以通过“实体继承”来把这两种“位置”(location)所共有的属性提取到父实体中。比方说,这个父实体可以叫做Location,它拥有名为summary的属性。而LocationAtHome实体或LocationAtShop实体则继承自Location,从而自动具备summary属性。这种行为与类的继承是相似的。
如果不想令父实体实例化,那么可将其标注为抽象的。只有能够确定Location实体的实例在代码中毫无意义时,才应该启用这个选项。
请按下列步骤修改Grocery Dude,以便配置实体及其继承关系:
1.基于Model 5来添加新的模型版本,并将其命名为Model 6。
2.将Model 6设为Current Model。
3.确保Model 6.xcdatamodel处于选定状态。
4.添加名为Location的新实体,并添加类型为String的属性,将其命名为summary。
5.选中Location实体,并在Utilities面板中打开Data Model Inspector界面,如图4-10所示。
6.勾选Abstract Entity,这将触发一条警告,提示开发者Location实体尚未有子实体。
7.创建名为LocationAtHome的新实体,并添加类型为String的属性,将其命名为storedIn。
8.创建名为LocationAtShop的新实体,并添加类型为String的属性,将其命名为aisle。
9.点击LocationAtHome实体,在Data Model Inspector界面(可按“Option++3”组合键调出该界面)中把Parent Entity(父实体)设为Location。
10.点击LocationAtShop实体,把Parent Entity设为Location。
11.如果编辑器当前不是Graph风格,那就将Editor Style切换到Graph,然后按照图4-10所示来排布各个实体。要是无法在一屏中看到所有实体,则可能需要滚动屏幕。
把新的父实体与子实体准备好之后,我们应该将其链接到Item实体,这样的话,item就可以同家中或商店中的某个位置相关联了。
请按下列步骤修改Grocery Dude,以便配置Item实体与LocationAtHome实体之间的“关系”:
1.按住Control键,用鼠标从LocationAtHome实体向Item实体拖曳一条线。
2.将LocationAtHome实体的newRelationship改名为items。
3.将LocationAtHome实体的items“关系”设为To-Many。
4.把Item实体的newRelationship改名为locationAtHome。
请按下列步骤修改Grocery Dude,以便配置Item实体与LocationAtShop实体之间的“关系”:
图4-10 作为抽象父实体的Location
1.按住Control键,用鼠标从LocationAtShop实体向Item实体拖曳一条线。
2.将LocationAtShop实体的newRelationship改名为items。
3.将LocationAtShop实体的items关系设为To-Many。
4.把Item实体的newRelationship改名为locationAtShop。
现在的模型应该与图4-11相符。请注意,双箭头表示“一对多关系”。
图4-11 新模型为Item添加了对“位置”的支持
请按下列步骤修改Grocery Dude,以便在代码中可以通过“点”(.)来访问新实体的属性:
1.为Model 6的所有实体都创建相应的NSManagedObject子类,并把原有的文件替换掉。在保存类文件的那一步里,记得勾选Targets中的“Grocery Dude”。
生成子类文件时,系统在生成顺序上可能会遇到“先有鸡还是先有蛋”的问题。这个问题会导致表示“一对一关系”的特性类型变成NSManagedObject,而正确的特性类型应该与“关系”的目标实例所具备的类型相同。图4-12演示了一份由Xcode所生成的Item.h文件,其中的特性类型是错误的。
图4-12 由Xcode所生成的NSManagedObject子类,其中的特性类型有误
至于哪些文件的特性类型会错误地变为基类类型NSManagedObject,这要看Xcode在生成子类文件时所采用的顺序。若想解决这个问题,只需按照前面的方式把子类文件重新生成一遍即可。图4-13演示了由Xcode再度生成的Item.h文件,而这次的特性类型则是正确的。为了避免这个问题,开发者可能得养成两次生成NSManagedObject子类的习惯,这样就不用每次都去检查子类文件的特性类型是否正确了。
图4-13 由Xcode再度生成的NSManagedObject子类,这次的特性类型是正确的
请按下列步骤修改Grocery Dude,以生成特性类型正确的子类文件:
1.再度根据Model 6中的所有实体来创建各自的NSManagedObject子类,并将原有的文件覆盖掉。