如何将修改后的地点名称写回存储,解决存储值不更新、storage调用报错问题
问题根因
- 第一版实现的核心缺陷:框架的
Place.find()方法只会把存储里的实体数据加载到内存做临时操作,修改内存对象的属性不会自动触发写回存储的逻辑,没有显式保存动作的话,所有内存层面的修改在当前方法执行结束后就会丢失,根本不会被持久化。 - 第二版手动写存储的代码存在两处硬伤,也是导致VS Code报类型错的直接原因:
- 存储键值逻辑完全错位:你错把
placeName(要修改的新地点名)当成了存储的key,把预设的默认值当成要存的value。代码里storage.get<string>(placeName, 'new galata tower')的查询目标是“以新地点名称为键的存储位置的内容”,和你要修改的、和placeId绑定的原有实体完全没有关联,写回去的数据也根本不会被getPlaces方法读取到。 - 入参类型不匹配:从上述
storage.get取出来的内容和你要持久化的地点实体没有任何关系,传给storage.set的参数完全不符合存储接口的要求,自然会触发代码报错。
- 存储键值逻辑完全错位:你错把
- 为什么
getPlaces读到的是旧值:这个读取方法是直接从底层持久化存储拉取数据的,你之前的操作全程没有修改过底层存储的内容,内存里的修改根本没同步到持久化层,自然读不到更新后的名称。
正确修正方案
推荐方式:使用实体自带的持久化方法
你当前使用的带实体模型的AssemblyScript生态开发框架,加载后的实体对象本身就提供了显式save()方法,修改完属性后调用这个方法,框架会自动把整个序列化后的实体写回对应的存储位置,完全不需要手动操作底层storage API:
export function changePlaceName(placeId: u32, placeName: string): void { assert(placeId >= 0, 'Place ID must be >= 0'); const place = Place.find(placeId); logging.log(place.name); // 此处读取的是存储加载的旧名称 "Galata Tower" place.name = placeName; // 显式调用保存方法,将修改后的实体持久化到存储 place.save(); logging.log(place.name); // 此处读取的是已写入存储的新名称 }
手动操作storage API的正确写法
如果出于特殊需求必须跳过实体封装直接操作底层storage,必须严格遵循实体类定义的存储键规则,不能随意用地点名称当存储key:
- 实体类在底层的存储位置是和
placeId一一绑定的,有固定的键名生成规则(一般格式为实体名:实体ID) - 写入时需要把完整的实体对象序列化后,写入到
placeId对应的固定键位置,不能拿业务属性(比如地点名称)当存储键
参考实现(需要替换为你项目中实际的键生成规则):
export function changePlaceName(placeId: u32, placeName: string): void { assert(placeId >= 0, 'Place ID must be >= 0'); const place = Place.find(placeId); place.name = placeName; // 按照项目定义的规则生成对应实体的存储键,不要硬编码随意生成 const placeStorageKey = Place.keyForId(placeId); // 序列化实体后写入对应存储键,完成持久化 storage.set<string>(placeStorageKey, place.encode()); }
内容的提问来源于stack exchange,提问作者Çağatay Soyer
相关产品推荐
相关产品推荐

