我希望使用数据存储来根据存储在数据库中的当前值更新一个值。在文档中,它显示了一个零售计数器用例。但是你应该如何实现这种设置呢?
一个小例子:
我有一张存货表,里面有一件物品和一件物品的柜台:
type Inventory @model {
id: ID!
name: String!
count: Int!}
如果我想保存一个新的Inventory
,我可以这样做:
Inventory inventory = Inventory(id,'product1',10);
Amplify.Datastore.save(inventory);
然后,我知道要更新,我可以使用相同的ID的Amplify.Datastore.save(inventoryUpdatedModel)
,而放大器将更新存储中的项目。到目前一切尚好。
那么,如果多个设备更改了与示例中相同的值,该怎么办?
开始:计数= 10;
1:设备1 ->将5添加到计数(10 +5= 15)
2:设备2 ->从计数中减去3(10-3= 7)
3:两种设备都更新数据存储和读取值。
目前,只显示最新的值(示例中为7),其中所需的答案为12。(10+5-3 = 12)
到目前为止,我已经尝试过:
我想要的是类似于这样的东西:Amplify.Datastore.updateValue(ID,-3);
扩增->采用旧值,减去3,用相同的命令更新appsync
发布于 2021-12-29 11:16:46
我选择的方向是这样的,如果我离目标很远,请随时告诉我!
基本上:运行一个服务来检测与AWS同步的补充表中的更改,并且只允许该服务在本地更改数据,而不是允许AWS更改本地受保护的表。
的优点:
缺点:
Make models:无法让模型通过代码代码直接获取相关对象(尽管看起来管道就是要这样做的)因此,我使用“表行”ID并执行两个Amplify.DataStore.query(model.classType)
操作来获取本地节点的inventory
,然后是泛型ticketitem
数据
type Inventory @model {
id:ID!
clientid: String!
inventoryclientid: String!
quantity:Int!
sellprice: Float!
ticketItemID: String!}
type TicketItem @model {
id:ID!
name: String!
buyprice: Float!
genericnfo: String!
}
type SyncedMutations @model {
id:ID!
clientid: String!
ownerclientid: String!
tablename: String!
itemid: String!
mutation: String!
from: String!
completed: [String]
itemdata: String!
}
然后:amplify codegen models
我还必须在启动时使用selectiveSync,如下所示:
AmplifyDataStore amplifyDataStore = AmplifyDataStore(modelProvider:
ModelProvider.instance, syncExpressions: [
DataStoreSyncExpression(SyncedMutations.classType, () => SyncedMutations.OWNERCLIENTID.eq(curClient))
DataStoreSyncExpression(Inventory.classType, () => Inventory.CLIENTID.eq(curClient)),
]);
Amplify.addPlugin(amplifyDataStore);
然后,我在启动时设置一个服务,以订阅和侦听发生在SyncedMutations
表上的事件,并在任何创建操作中更新本地inventory
表。代码如下(需要清理):
import ...
@LazySingleton()
class SyncMutationsService {
static final SyncMutationsService _instance = SyncMutationsService._internal();
final _clientService = locator<ClientService>();
SyncMutationsService._internal() {
Stream<SubscriptionEvent<SyncedMutations>> stream = Amplify.DataStore.observe(SyncedMutations.classType)
..listen(handleSubscription);
}
factory SyncMutationsService() => _instance;
handleSubscription(SubscriptionEvent<SyncedMutations> event) async {
if (event.eventType == EventType.create) {
updateLocalProtectedTable(event.item);
}
}
void updateLocalProtectedTable(SyncedMutations eventitem) {
switch (eventitem.tablename) {
case 'Inventory':
print('Inventory table update.. ');
updateInventoryOnEvent(eventitem);
break;
}
}
void updateInventoryOnEvent(SyncedMutations eventitem) {
try {
Inventory inventorydata = Inventory.fromJson(json.decode(eventitem.itemdata));
SharedPreferencesHelper.getCurrentClientID().then((curClientID) {
if (eventitem.completed == null || !eventitem.completed!.contains(curClientID)) {
try {
if (int.tryParse(eventitem.mutation) != null) {
getCorrespondingInventoryLine(inventorydata.inventoryTicketItemID).then((oldLocalInvItem) {
Inventory updatedInventoryItem = oldInvItem.copyWith(
quantity: oldLocalInvItem.quantity + int.parse(eventitem.mutation),
);
Amplify.DataStore.save(updatedInventoryItem).then((value) {
//update syncMutationLine completed client list
List<String> completedList = eventitem.completed ?? [];
completedList.add(_clientService.client.id);
Amplify.DataStore.save(eventitem.copyWith(completed: completedList));
});
});
}
} catch (e) {
print('TicketItem was saved, but could not initialise stock into Inventory. ERROR: $e');
}
}
});
} catch (e) {
print('Could not transpose inventory line data from syncMutation. ERROR: $e');
}
}
Future<Inventory> getCorrespondingInventoryLine(String ticketItemID) async {
double markup = await SharedPreferencesHelper.getBaseMarkup();
return Amplify.DataStore.query(Inventory.classType).then((inventoryList) {
return Amplify.DataStore.query(TicketItem.classType).then((ticketItemList) {
TicketItem ti = ticketItemList.firstWhere((tItem) => tItem.id == ticketItemID);
if (inventoryList.isNotEmpty) {
return inventoryList.firstWhere((inventoryLine) => inventoryLine.inventoryTicketItemID == ticketItemID,
orElse: () {
return Inventory(
clientid: _clientService.client.id,
inventoryclientid: _clientService.client.id,
quantity: 0,
sellprice: markup * ti.buyprice,
inventoryTicketItemID: ticketItemID);
});
} else {
return Inventory(
clientid: _clientService.client.id,
inventoryclientid: _clientService.client.id,
quantity: 0,
sellprice: markup * ti.buyprice,
inventoryTicketItemID: ticketItemID);
}
});
});
}
}
现在,每当我想调整库存数量(或使用相同逻辑的任何其他表)时,我在本地直接保存到inventory
,然后添加一个带有当前设备的clientID的syncedMutations
条目,该条目将被派生给所有更改相同信息的其他客户端。就像这样:
Inventory updatedInventoryItem = oldInventoryItem.copyWith(
quantity:oldInventoryItem.quantity+valueOfMutation);
int mutationInt = valueOfMutation; // add 10, minus 4 etc
Amplify.DataStore.save(updatedInventoryItem).then((value) {
Amplify.DataStore.save(SyncedMutations(
clientid: clientService.client.id,
ownerclientid: clientService.actingClient.id,
completed: [clientService.client.id],
tablename: 'Inventory',
itemid: oldInventoryItem.ticketItemID,
mutation: mutationInt.toString(),
from: oldInventoryItem.quantity.toString(),
itemdata: json.encode(updatedInventoryItem.toJson())));
});
因此,假设我有两个客户端,它们都有间歇性的网络,而且不一定同时运行,当更新发生时,每个设备都会更改自己的库存,然后在网络连接时,将每个突变操作发送到云中,以找到具有相同clientID
的任何其他设备,然后syncMutations会侦听create事件,并对其本地(但在线备份)版本的库存进行自己的更新。然后,它还将自己的clientID
添加到最新的客户端列表中。
稍后,您可以运行一个测试,以摆脱所有syncedMutations,这些syncedMutations中的每个客户端都在完整的列表中。
我确信有一个更好或更健壮的方法来解决这个问题,但是它可以像预期的那样工作,同时将所有的逻辑都保存在设备上。
https://stackoverflow.com/questions/70384827
复制相似问题