天啊。你的代码有大麻烦!在深入研究细节之前,跳出页面的是您可能会在episodes
每次数组更改时重复地向数组中的每一集添加订阅。哎呀!
事件传播延迟
在我继续我的疑虑之前,我想承认您的具体经验,即您的听众何时触发与manager.hasChanges
. 那是真的。KO 订阅在EntityManager
听说更改之前就被触发了……这就是它报告错误的原因。变化的消息还没有到经理听到。
我也注意到了这一点。事实上,如果您查看TodoSample中的viewModel.js,您会发现我们通过添加一个setTimeout
来解决它,让 Breeze 有机会听到更改:
// 使用 Breeze PropertyChanged 事件监听变化
item.entityAspect.propertyChanged.subscribe(function () {
if (suspendItemSave) { return; }
// 给 EntityManager 时间来听到变化
setTimeout(saveIfModified, 0);
函数 saveIfModified() {
if (item.entityAspect.entityState.isModified()) {
数据服务.saveChanges();
}
}
});
我希望我知道另一种方式。那只是KO和Breeze之间的时间问题。我们还没有弄清楚如何巧妙地处理它。不确定我们能否做到。
模型规则还是视图规则?
让我们备份。无论它出现在什么视图中,都应该episode
在其listenedTo
属性更改时保存吗? 如果您的回答是“是”,那么您有一个真正属于该模型的应用程序业务规则,并且您确实需要监听情节变化的东西。
但是如果答案是“否”......如果保存应该由“复选框”触发,而不是对对象的更改,那么这是一个 UI 规则......一个视图规则......你应该使用 KO听checkbox,而不是 episode 属性。
实体更改时保存
让我们来看第一种情况,并断言您的应用程序规则如下:“总是在listenedTo
更改时保存,无论是什么原因导致它更改”。
我知道在TodoSample中,我们演示了一种直接监听实体以更改其一个属性(其任何属性)的方法。这很强大,而且很直观。
我开始相信这不是最安全的方法。在具有共享同一实体的多个 ViewModel 的应用程序中,它可能会导致内存泄漏。这个“待办事项”应用程序只有一个屏幕,因此不必担心。但在更大的应用程序中......我会担心。
所以我建议不要监听Episode
属性的变化。而是听EntityManager
! 查看最近发布的Breeze SPA 模板中datacontext.js的这个片段。
功能 configureManagerToSaveModifiedItemImmediately() {
manager.entityChanged.subscribe(entityStateChanged);
功能实体状态改变(参数){
如果(args.entityAction === 微风.EntityAction.EntityStateChange){
var 实体 = args.entity;
if (entity.entityAspect.entityState.isModified()) {
保存实体(实体);
}
}
}
}
注意它如何监听 EntityManager 缓存的任何实体的状态变化。它只对转换到“已修改”状态感兴趣。检测到时,它会保存实体。
现在这对你来说可能太宽泛了。但是您可以想象注册额外的过滤逻辑来满足您的应用程序的特定需求。
保存队列
与自动保存有关的新问题。无论您如何触发保存,这个问题都很重要。
用户可以很快点击。她一定会比处理请求更快地触发保存请求。Breeze(默认情况下)EntityManager
在等待服务器从挂起的保存操作返回结果时不会再次保存。它会抛出异常。
它必须等待,因为它无法将实体的状态从已更改更改为未更改,直到它知道保存是否成功。如果保存失败,您希望将实体保持在“未保存”状态。
查看datacontext.js顶部的manager.enableSaveQueuing(true)
. 这不是微风的原生功能。这是插件的一个功能,Scripts/breeze.savequeuing.js 你会想要加载这个插件。在Breeze SPA 模板的文章中阅读它
为什么这么复杂
你可能认为Breeze这个东西非常复杂。实际上,引入复杂功能的不是 Breeze。您希望在实体更改其状态时触发保存,这会增加复杂性。
我并不是说你这样做是错误的。我的意思是,这种方法是 Breeze 提供的一个机会,在实施过程中需要小心谨慎。
如果没有 Breeze,您将完全无法跟踪实体状态。因此,您唯一真正安全的选择是根据对复选框的更改来触发保存……在这种情况下,所做的工作并不比将 KO 绑定到复选框更复杂。
嗯......好吧......由于您绊倒的Breeze / KO时间问题,它有点复杂,这需要setTimeout
开局。但我希望你能明白我的意思。