0

我可能没有很好地解释这个......

我正在使用微风 js 实现一个实体,该实体包含近 100 个浮点字段。这些是计算结果字段,其中有 4 个单独的部分,然后是总计,并且重复 19 次。所以 19 x 5 = 95 个字段,因此“接近 100”。

基本上是:

calculationResult1_materials 
calculationResult1_processes 
calculationResult1_packaging 
calculationResult1_transport 
calculationResult1_total 

calculationResult2_materials 
calculationResult2_processes 
calculationResult2_packaging 
calculationResult2_transport 
calculationResult2_total 

calculationResult3_materials 
etc...

看起来很明显,“总计”字段包含其他 4 个部分的总和,但也被存储,因为有一个仅访问该字段的遗留系统,这可以防止每次有人想要查看总计时都必须完成总和.

由于微风将总字段具体化为与其他字段一样的普通可观察对象,这意味着每次我为任何计算重新计算其他 4 个字段中的任何一个时,我都必须手动重新汇总 4 个单独的组成部分(材料,包装,处理,运输)并将结果放入“总”可观察对象中,该可观察对象绑定到显示它的html页面中的div。

虽然这可行,但让我感到震惊的是,这可能不是最有效的做事方式。显然,我可以在我的 viewmodel 中独立创建 19 个 computedObservables,其中包含每个计算的 4 个其他字段,然后绑定到该字段而不是每个实际的“total” observable,但这意味着如果字段名称发生更改,则需要手动更新代码。

有没有办法以某种方式将可观察对象重新定义为可计算的可观察对象,以便每当计算的其他 4 个部分中的任何一个发生更改时它都会自动计算,并且仍然是实体的一部分,以便之后微风保存更改?

4

2 回答 2

2

我不会使用 KO 计算!

相反,在自定义初始化程序中,我将订阅 BreezeEntityAspect.propertyChanged事件,并在 EntityType 的原型中添加一个重新计算函数)。

一旦您确定了基于更改的属性名称更新总计的模式,这将是更轻的重量(一种方法而不是 1000 秒)、更高的性能和更易于维护。

代码看起来像这样:

function calculationResultCtor() {/*... stuff in the ctor */ }

calculationResultCtor.recalcTotals(propertyName, newValue)
    /* do whatever based on the newValue and the propertyName 
       remember to use the parens required by KO observables
    */
}

function calculationResultInitializer(cr) {
   // listen for any property change in this calculationResult instance
   cr.entityAspect.propertyChanged.subscribe(function(args){
        var propName = args.propertyName;
        if (/_total/.test(propName)) return; // skip changes to total properties
        args.entity.recalcTotals(propName, args.newValue);
   });
}

metadataStore.registerEntityTypeCtor('CalculationResult', 
    calculationResultCtor, calculationResultInitializer);

我可以想出更聪明的方法(例如,计算 fns 的字典,由 键控propertyName)来提高效率,但你知道我要去哪里。

我要担心的一件事(如果这是一个问题,那么您的 KO 计算方法也将是一个问题)是我所说的“propertyChanged”风暴,其中一些自动化过程会同时更新许多属性。

解决方案 - 如果这是一个问题,我不是说它是 - 将锁定 recalc 事件,以便它在风暴期间终止,然后,当它结束时,您只需一次重新计算每个总数通过实体。

重要的一点是我开始的地方:不要创建 1000 次 KO 计算!是的,将有 1000 个,因为您的计划将为每个实体添加至少 19 个计算,因此仅 53 个实体实例就会使您超过 1000 个。这不好。

于 2013-11-13T07:16:46.613 回答
1

您的应用程序中应该有类似“model.js”的内容,您可以在其中定义 Breeze 如何处理数据。您应该公开功能configureMetadataStore并在那里放置功能:

function configureMetadataStore(metadataStore){
  metadataStore.registerEntityTypeCtor('MyContainerClassFromServerModel', null, thisClassInitializer);

之后,您需要定义thisClassInitializer告诉 Breeze 做什么的地方,正如您所说的,“物化对象”:

function thisClassInitializer(myObject){
  myObject.customTotal = ko.computed({
    read: function(){
      return myObject.materials() + myObject.processes() + myObject.packaging() + myObject.transport();
    },
    write: function(newValue){
      myObject.total(newValue);
    }
  });
}

这应该可以解决问题。或者我刚刚想到的,您可以将其定义为:

function thisClassInitializer(myObject){
  myObject.customTotal = ko.computed({
    var newValue = myObject.materials() + myObject.processes() + myObject.packaging() + myObject.transport();
    myObject.total(newValue);
    return newValue;
  });
}

不同之处在于,对于第一个我不能保证不尝试它(对这个 ko 绑定不是那么熟练),但对于另一个我很确定它应该可以工作。

说明:当你定义这样的东西时,每当 Breeze 将服务器中的对象“物化”为可观察对象时,它也会调用初始化程序。通过这种方式,您可以修改对象具有的字段 - 通常您将计算值放在那里(例如总计),因此您也不需要将其保存在服务器上。理想情况下,您不需要服务器上的“总计”,因为它不包含其他信息 - 所有信息都在其他变量中,并且可以计算此值。

于 2013-11-12T10:16:05.907 回答