需要一种策略来实现部分更新服务调用,而无需重新发明轮子

时间:2015-01-29 01:56:06

标签: ember.js ember-data

我的后端有一些很酷的功能,我正在努力实施。用例子更容易解释......

假设您有订单,订单行(定义为hasMany)和用户当前正在编辑的附加产品,他们会更改一行的价格。在功能上,您想要重新计算销售税作为示例。

我的后端允许我打包并发送此瞬态对象(以及更改的字段列表),并确定需要在对象树上更改的内容(尚未实际持久保存该对象)。它返回的是一个稀疏填充的对象,其值已在服务器端更改。

所以,如果我有这样的事情:

{
  orderid: '12345',
  taxamt: 0,
  lines: [
    {
      id: 1,
      product: 'ABC',
      price: 99.99
    }
  ]
}

然后,让我们说,用户更新线路价格。如果我把它发送到后端:

{
  orderid: '12345',
  taxamt: 0,
  lines: [
    {
      id: 1,
      product: 'ABC',
      price: 89.99
    }
  ],
  changelist: ['lines.price']
}

......我会回来这样的事情:

{
  orderid: '12345',
  taxamt: 12.00,
}

...也就是说,我已经足够唯一地识别每个对象,然后只识别服务器端更新的属性。

我已经实现了上半部分,但处理回报证明是困难的。我已经部分工作了,但我确实觉得我正在重新实施大量的余烬数据。

鉴于服务器可能会添加或删除关系对象,并且可能会改变任何级别的任何属性,哪种方法最好地利用现有框架?

更新:请注意我不是一个余烬数据noob :)我找到并保存了自定义序列化器等工作,以处理不符合要求的JSON。

我无法更改后端,因为我们已经有一个现有的客户端应用程序在生产中使用它,我无法破坏。

我在这里描述的场景既不是发现也不是保存 - 我需要创建自定义。该示例旨在描绘我刚刚开始在客户端上创建的新订单。服务器还不知道这个对象。在我的例子中,为了近乎实时地计算税收,我称之为"更新"端点让服务器对瞬态对象执行该计算,它不会保存数据库,但会在服务器上执行任何计算和处理以及业务逻辑,并将更改发送回客户端。它以这种方式工作的原因是从客户端应用程序中删除税务计算等业务逻辑(甚至需要知道何时进行计算)。

2 个答案:

答案 0 :(得分:0)

您的案例似乎是ember数据的标准案例。你读过这篇文章:http://emberjs.com/guides/models/connecting-to-an-http-server/

了解URL和JSON约定,您应该最终使用标准的this.store.find(' order'),this.store.find('order', id)newOrder.save()方法。

鉴于您提供的JSON,在前端方面似乎不需要changelist,所以除非您真的需要在后端,否则我不会把它放在那里。 / p>

由于您可以完全控制后端,我会将orderid更改为id - 然后您不必更改任何内容。

响应可能是完整的记录响应。如果您始终与数据保持一致,那么它就会变得更容易。而且,我会稍微改变结构(见下文)。

在这种情况下应该起作用的是:

var OrderModel = DS.Model.extend({
  taxamt: DS.attr('number'),
  lines: DS.hasMany('line')
});

var LineModel = DS.Model.extend({
  product: DS.attr('string'),
  price: DS.attr('number')
});

然后,如果你想获得一个order(使用this.store.find('order', 12345),你的JSON应该是这样的:

{
  "order": {
    "id": '12345',
    "taxamt": 0,
    "lines": [1]
  },
  "line": [{
    "id": 1,
    "product": 'ABC',
    "price": 99.99
  }]
}

如果您不想改变后端的行为,可以随时使用序列化程序及其normalizePayload方法。简化示例:

var OrderSerializer = DS.RESTSerializer.extend({
  normalizePayload: function(payload) {
    return {
      "order": payload
    };
  }
});

将接受此有效负载:

{
  "id": 12345,
  "taxamt": 0
}

并将其转换为:

{
  "order": {
    "id": 12345,
    "taxamt": 0
  }
}

我希望这有帮助!

答案 1 :(得分:0)

我只需要咬紧牙关,花一些时间在ember数据源代码上。 :)

事实证明,这很容易做到.......一旦你将手臂环绕在余烬数据的内部以及它正在做的事情上。

我已经实施了观察者端来检测并启动更新呼叫(参见EmberJS dynamic observers at run-time?

这一切都是在我的应用程序适配器上启动了一个去抖动的$ .ajax调用。诀窍是,如何处理响应。

事实证明,我真正需要做的就是......

getUpdates: function() {
    var store = this.autoUpdateContext.store;
    var type = this.autoUpdateContext.type;
    var record = this.autoUpdateContext.record;
    var className = this.autoUpdateContext.className;
    var url = this.autoUpdateContext.url;
    var self = this;

    var serializedRecord = self._serializeForService(record);
    var data = {};

    data[className] = serializedRecord;
    data = self._mergeParams(data);

    var serializer = store.serializerFor(record.constructor.typeKey);

    var also_managing = serializer.get('also_managing');
    if(also_managing !== null) {
      data['also_managing'] = JSON.stringify(also_managing);
    }

    Ember.$.ajax({
      type: 'POST',
      url: url,
      dataType: 'json',
      data: data
    }).then(function(data) {
      //THIS IS THE IMPORTANT STEP HERE...THESE NEXT TWO LINES
      var payload = serializer.extract(store, type, data, record.get('id'), 'updateRecord');
      return store.push(type, payload);
    }, function(jqXHR) {
      console.log('Error getting updates'+jqXHR);
    });
  },

因此,调用serializer.extract将运行我需要的所有extractMeta和normalizer内容,以及EmbeddedRecords混合内容。 ' udpateRecord'有点不是非常重要,但它最接近于对这是做什么的想法。

store.push显然可以很好地处理稀疏填充的返回值......很好!

这需要进行更多清理,我最终可能会最终将其移至商店,但似乎可以正常工作。