在BOTH上保存关系以Ember Data结束

时间:2014-10-14 12:49:28

标签: ember.js ember-data

我正在使用Ember Data和RestAdapter以及以下模型:

Pizzas.Pizza = DS.Model.extend({
  name: DS.attr('string'),
  orders: DS.hasMany('order', { async: true }),
});

Pizzas.Order = DS.Model.extend({
  date: DS.attr('date'),
  pizzas: DS.hasMany('pizza', { async: true }),
});

我按如下方式创建并保存新订单:

var pizza1 = an existing pizza with id 1;
var pizza2 = an existing pizza with id 2;

var newOrder = this.store.createRecord('order');
newOrder.set('date', Date());

newOrder.get('pizzas').then(function(pizzas) {

    pizzas.pushObject(pizza1);
    pizzas.pushObject(pizza2);
    newOrder.save();
});

这很有效--Ember Data在Order模型上执行POST,其中包含pizzas关系字段中比萨饼的ID。但是,我预计在保存之后,订单ID将自动添加到Ember Data的2个披萨对象的orders关系中,但似乎并非如此。这导致了两个问题:

  1. 当我要求披萨的所有订单时,新订单不会出现(因为它从未被添加到披萨的关系字段中)
  2. 当对比萨饼进行更改(例如名称更改)并保存比萨饼时,新的订单关系在服务器上丢失(因为它从未添加到比萨饼的关系字段中,而PUT仅包含订单最后一次从服务器获取的ID)
  3. 我通过修改上面的最后一行代码来解决这个问题,如下所示:

    newOrder.save().then(function() {
    
            pizza1.get('orders').then(function(orders) {
    
                orders.pushObject(newOrder);
            })
            // same for pizza 2
        } );
    

    Ember数据是否要求双方手动创建关系(正如我所做的那样)或者我错过了什么?

1 个答案:

答案 0 :(得分:2)

我正在使用来自我自己的分支的beta 11 plus补丁。

持久的关系是您需要自己管理的事情。 Ember Data中不存在任何硬性或快速规则,因为不同的服务器和json apis将有不同的方法来管理关系以及特定的验证和参照完整性规则,这些规则将决定如何管理模型之间的关系。这将在模型持久性状态中引入排序依赖性。如果你有一个松散的" NoSQL"类型文档服务器没有这样的参照完整性要求,因此事情看起来很容易,最终的数据不一致现实,孤儿,悬挂引用等等。

请注意声称可以解决问题的客户端数据持久层,因为实际上它们只适用于某些狭窄的用例。它实际上只是在控制器中编排保存的问题,其中知识和需要完成的工作环境属于。

我发现在json apis中运行良好的策略是简单地管理具有外键的模型上的关系(即" belongsTo" side)并避免在hasMany端返回或管理键作为当你的收藏增长时,所有被传递的身份都不能很好地扩展。

最好查看JSONSerializer基类的源代码,其中序列化模型以查看它的作用,RESTSerializer继承其行为。您将看到序列化程序只保存ID,并且不会通过对象图递归级联保存,这将是一件坏事,因为您试图解决NP-Complete Hamiltonian Path Problem!。这就是为什么我说非常怀疑数据层做出承诺来解决你的模型图持久性问题,而只是编排你需要在控制器中完成的事情。这也与脏跟踪和缓冲更改很好地对齐(例如使用a buffered proxy)。

<强>更新

我忘了添加一些相当明显的东西,但是您可以定义自己的模型序列化程序,可以将任何相关模型作为单个POST / PUT事务(而不是使用.then方法)的一部分进行侧面保存,具体取决于在您的服务器支持。只需覆盖相关的序列化方法即可包含您需要的内容。如果你有一些非常密切相关的模型总是一起创建或更新,EmbeddedRecordsMixin也会很有用。

例如,我有联系人模型,其中每个联系人可以有一个或多个姓名,地址,电子邮件或网址。每个模型都是跟踪偏好/目的的模型,以及validFrom / validTo等等。

首先,我的应用程序序列化器混合了嵌入式记录支持和attrs属性的合并,因此我可以继承序列化器:

// app/serializers/application.js
import DS from 'ember-data';

export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin,{
  mergedProperties: [ 'attrs' ]
});

然后我的Contact序列化程序指定嵌入了哪些模型:

// app/serializers/contact.js
import AppSerializer from "./application";

export default AppSerializer.extend({
  attrs: {
    names: { embedded: 'always'},
    addresses: { embedded: 'always' },
    emails: { embedded: 'always' },
    phones: { embedded: 'always' },
    urls: { embedded: 'always' }
  }
});