Javascript Breeze.js EntityManager未检测到更改

Javascript Breeze.js EntityManager未检测到更改,javascript,mvvm,knockout.js,breeze,Javascript,Mvvm,Knockout.js,Breeze,我的viewmodel如下所示,使用knockout.js绑定到我的页面。剧集是一个实体数组,每个实体都有一个布尔属性“ListedTo”绑定到我的页面上的复选框 function episodesViewModel() { this.episodes = ko.observableArray(); this.sync = function () { repository.populateEpisodes(this); } this.save

我的viewmodel如下所示,使用knockout.js绑定到我的页面。剧集是一个实体数组,每个实体都有一个布尔属性“ListedTo”绑定到我的页面上的复选框

function episodesViewModel() {

    this.episodes = ko.observableArray();

    this.sync = function () {
        repository.populateEpisodes(this);
    }

    this.save = function () {
        repository.saveChanges();
    }

    //this.episodes.subscribe(function (episodes) {
    //    ko.utils.arrayForEach(episodes, function (episode) {
    //        episode.ListenedTo.subscribe(function () {
    //            window.repository.saveChanges();
    //        });
    //    });
    //});

    // perform an initial sync
    this.sync();   
}
repository对象只是底层Breeze调用的包装器

如果我将save()绑定到一个按钮单击,那么一切都会按预期进行,breeze会看到有更改并调用服务器。如果我取消对创建ListenedToChange订阅的行的注释(并保存而无需单击按钮),那么奇怪的事情就会发生

页面加载并填充后,第一次单击复选框将按预期自动调用breeze saveChanges()。即使viewmodel中的值与预期值一致并与复选框匹配,breeze hasChanges()仍返回false,并且不进行任何服务器调用。再次单击它,hasChanges现在为true,并进行服务器调用!?这就好像Breeze落后了,没有在viewmodel上注册对实体的更改


有什么想法吗?

没有更多信息就很难知道(例如,使用了哪些其他框架,什么触发了VM实例化代码,KO.ApplyBind在哪里) 在创建VM时,视图是否正确构造

我现在使用的是Durandal,它首先创建VM,然后创建视图。在Durandal的激活事件期间(或更早的事件,如实例化代码)尝试创建附加订阅,导致KO视图/视图模型订阅被释放,因为它们被发现无效。我必须在Durandal后来的viewAttached事件中创建订阅


尝试稍后将订阅放入工作流中。

如果没有更多信息,很难知道(例如,使用了哪些其他框架,什么触发了VM实例化代码,KO.ApplyBind在哪里) 在创建VM时,视图是否正确构造

我现在使用的是Durandal,它首先创建VM,然后创建视图。在Durandal的激活事件期间(或更早的事件,如实例化代码)尝试创建附加订阅,导致KO视图/视图模型订阅被释放,因为它们被发现无效。我必须在Durandal后来的viewAttached事件中创建订阅


尝试稍后将您的订阅放入工作流。

哦,天哪。你的代码有大问题!在深入研究细节之前,跳出页面的可能是每次数组更改时,您都会重复向
剧集
数组中的每一集添加订阅。哎呀

事件传播延迟 在我继续谈论我的疑虑之前,我想承认您的具体经历,即您的听众发出的声音与
manager.hasChanges
的价值不一致。那是真的。KO订阅在
EntityManager
听说更改之前启动。。。这就是它报告错误的原因。变化的消息还没有传到经理那里

我也注意到了这一点。事实上,如果您查看中的viewModel.js,您将看到我们通过添加
setTimeout
来解决它,让Breeze有机会听到更改:

// listen for changes with Breeze PropertyChanged event item.entityAspect.propertyChanged.subscribe(function () { if (suspendItemSave) { return; } // give EntityManager time to hear the change setTimeout(saveIfModified, 0); function saveIfModified() { if (item.entityAspect.entityState.isModified()) { dataservice.saveChanges(); } } }); 注意它如何侦听EntityManager缓存的任何实体中的状态更改。它只对转换到“修改”状态感兴趣。检测到时,它会保存实体

这对你来说可能太宽了。但是您可以想象注册额外的过滤逻辑来满足应用程序的特定需求

存储队列 新问题与自动保存有关。无论您如何触发保存,此问题都很重要

用户可以很快点击。她触发保存请求的速度肯定比处理请求的速度快。Breeze(默认情况下)在等待服务器返回挂起的保存操作的结果时,不会让EntityManager再次保存。它将抛出一个异常

它必须等待,因为在知道保存是否成功之前,它无法将实体的状态从“已更改”更改为“未更改”。如果保存失败,您希望将实体保持在“未保存”状态

查看datacontext.js顶部的
manager.enableSaveQueuing(true)
。这不是微风的固有特征。这是一个插件的功能,Scripts/breeze.savequeuing.js您需要加载这个插件。请在本期的专栏文章中阅读

为什么这么复杂 你可能会认为这件事非常复杂。事实上,并不是微风带来了复杂性。您希望在实体更改其状态时触发保存,这会增加复杂性

我不是说你这样做是错的。我的意思是,这种方法是Breeze提供的一个机会,它在实施过程中会采取一些谨慎措施

如果没有Breeze,您将有一个魔鬼般的时间来跟踪实体状态。因此,您唯一真正安全的选择是根据对复选框的更改触发保存。。。在这种情况下,工作并不比绑定到复选框的KO复杂


嗯。。。好啊由于您遇到的Breeze/KO计时问题,这就需要执行
setTimeout
gambit,因此它有点复杂。但我希望你明白我的意思。

哦,天啊。你的代码有大问题!在深入研究细节之前,跳出页面的可能是每次数组更改时,您都会重复向
剧集
数组中的每一集添加订阅。哎呀

事件传播延迟 在我继续谈论我的疑虑之前,我想承认您的具体经历,即您的听众发出的声音与
manager.hasChanges
的价值不一致。那是真的。KO订阅在
EntityManager
听说更改之前启动。。。这就是它报告错误的原因。变化的消息还没有传到经理那里

我注意到了这一点 function configureManagerToSaveModifiedItemImmediately() { manager.entityChanged.subscribe(entityStateChanged); function entityStateChanged(args) { if (args.entityAction === breeze.EntityAction.EntityStateChange) { var entity = args.entity; if (entity.entityAspect.entityState.isModified()) { saveEntity(entity); } } } }