我选择的方向是这样的,如果我偏离了标记,请随时告诉我!
基本上:
运行一项服务来检测与 AWS 同步的补充表中的更改,并且只允许此服务在本地更改数据,而不是允许 AWS 更改您在本地受保护的表。
优点:
- 根本不依赖任何服务器代码。
- 间歇性网络很好,更新在多个设备上保持不变,
- 仅使用颤振放大 api
缺点:
制作模型:无法让模型直接通过 codegen'd 代码获取相关对象,(即使看起来有管道可以做到这一点..)所以我使用 'table行的 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。
我确信有更好或更强大的方法来解决这个问题,但它可以按预期工作,同时将所有逻辑保留在设备上。