【问题标题】:Ember Data: Saving relationshipsEmber 数据:保存关系
【发布时间】:2014-11-09 08:25:00
【问题描述】:

我需要一次将一个深度对象保存到服务器,并且无法在网上找到任何使用最新 ember 数据 (1.0.0-beta.4) 的示例。

例如,对于这些模型: (jsfiddle)

App.Child = DS.Model.extend({
    name: DS.attr('string'),
    age: DS.attr('number'),
    toys: DS.hasMany('toy', {async:true, embedded:'always'}),
});
App.Toy = DS.Model.extend({
    name: DS.attr('string'),
    child: DS.belongsTo('child')
});

还有这段代码:

actions: {
    save: function(){
        var store = this.get('store'),
            child, toy;

        child = store.createRecord('child', {
            name: 'Herbert'
        });
        toy = store.createRecord('toy', {
            name: 'Kazoo'
        });

        child.set('toys', [toy]);
        child.save();
    }
}  

它只保存子对象的 JSON,但不保存任何玩具——甚至没有侧面加载:

{
  child: {
    age: null
    name: "Herbert"
  }
}

我也必须手动保存玩具吗?无论如何,我可以让它将以下 JSON 发送到服务器:

{
  child: {
    age: null
    name: "Herbert",
    toys: [{
        name: "Kazoo"
    }]
  }
}

或者

{
  child: {
    age: null
    name: "Herbert",
    toys: [1]
  }
}

参见 JSFiddle:http://jsfiddle.net/jgillick/LNXyp/2/

【问题讨论】:

    标签: json ember.js ember-data


    【解决方案1】:

    这里的答案已经过时了。 Ember Data 现在支持嵌入式记录,这使您可以准确地执行您想要做的事情,即在一个大负载中获取和发送完整的对象图。例如,如果您的模型是这样设置的:

    App.Child = DS.Model.extend({
        name: DS.attr('string'),
        age: DS.attr('number'),
        toys: DS.hasMany('toy')
    });
    App.Toy = DS.Model.extend({
        name: DS.attr('string'),
        child: DS.belongsTo('child')
    });
    

    您可以为您的 Child 模型定义自定义序列化程序:

    App.ChildSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
      attrs: {
        toys: {embedded: 'always'}
      }
    });
    

    这告诉 Ember Data 您希望将“玩具”作为“子”负载的一部分包含在内。您的 API 的 HTTP GET 响应应如下所示:

    {
      "child": {
        "id": 1,
        "name": "Todd Smith",
        "age": 5,
        "toys": [
          {"id": 1, "name": "boat"},
          {"id": 2, "name": "truck"}
        ]
      }
    }
    

    当您保存模型时,Ember Data 会将其发送到服务器:

    {  
       "child":{  
          "name":"Todd Smith",
          "age":5,
          "toys":[  
             {  
                "id":"1",
                "name":"boat",
                "child":"1"
             },
             {  
                "id":"2",
                "name":"truck",
                "child":"1"
             }
          ]
       }
    }
    

    这是一个演示这个的 JSBin。

    http://emberjs.jsbin.com/cufaxe/3/edit?html,js,output

    在 JSbin 中,当您单击“保存”按钮时,您需要使用 Dev Inspector 查看发送到服务器的请求。

    【讨论】:

    • 您知道这是否是首选方法吗?我的理解是,在 GET 响应中包含嵌入式记录并不总是最有效的。但是,我可以看到在发出 POST/PUT 请求时嵌入记录的好处。
    • @antony,您提出的 API 设计问题并非专门针对 Ember Data。如果您相信聚合(例如,订单有订单商品,但订单商品本身没有身份),那么您将需要使用嵌入记录。此外,如果您需要在一个原子事务中进行更新(例如再次订购和订购商品),那么您将需要使用嵌入式记录。但是,如果每个模型都可以有自己的可识别端点,那么嵌入式记录就没有意义了。
    【解决方案2】:

    玩具不能总是既异步又嵌入,这些是相互矛盾的选项。 Embedded 目前仅存在于活动模型序列化器上。

    toys: DS.hasMany('toy', {embedded:'always'})
    

    玩具是多对一关系,由于关系存在于 belongsTo 端,因此在玩具保存期间保存关系会更有效。话虽如此,如果您一次创建所有内容,则希望将其保存在一大块中,这就是覆盖发挥作用的地方。

    serializeHasMany: function(record, json, relationship) {
      var key = relationship.key;
    
      var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
    
      if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
          relationshipType === 'manyToOne') {
        json[key] = get(record, key).mapBy('id');
        // TODO support for polymorphic manyToNone and manyToMany relationships
      }
     },
    

    你的存档应该是这样的

        var store = this.get('store'),
            child, toy;
    
        child = store.createRecord('child', {
            name: 'Herbert'
        });
        toy = store.createRecord('toy', {
            name: 'Kazoo'
        });
    
        child.get('toys').pushObject(toy);
        child.save().then(function(){
           toy.save();
        },
        function(err){
          alert('error', err);
        });
    

    【讨论】:

    • toys 在哪里定义?在您调用的行上:toys.save() 如果您的意思是child.get('toys').save(),或者访问承诺的响应,那么该调用是保存在每个单独的模型上还是一次保存它们?我和 Jeremy 有同样的问题,当我尝试调试/检查 hasMany 属性时,就像在这种情况下查看 child.get('toys') 甚至在我在那里推送新记录之后,数组中的值是 null .我认为这是因为 Ember-Data 知道将玩具的 id 存储在玩具数组中,但玩具还没有 id,因为它没有被保存。
    • 是的,应该是toy,我正在保存单个玩具。
    • 所以如果我理解正确的话。我们设置了具有相互一对多关系的模型,Child hasMany Toys 和 Toy belongsTo Child。在内部,玩具模型上将有一个 childId 属性,它实际上将被持久化。当你调用child.pushObject(toy)时,两者的关系就建立了,一旦保存了child,玩具的childId属性会自动更新吗?我希望您必须在承诺履行处理程序中调用 toy.set('child', response)
    【解决方案3】:

    我需要一个深的物体,而不是一个侧面加载的物体,所以根据 kingpin2k 的回答,我想出了这个:

    DS.JSONSerializer.reopen({
        serializeHasMany: function(record, json, relationship) {
            var key = relationship.key,
                property = Ember.get(record, key),
                relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
    
            if (property && relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
                relationshipType === 'manyToOne') {
    
                // Add each serialized nested object
                json[key] = [];
                property.forEach(function(item, index){
                    json[key].push(item.serialize());
                });
            }
        }
    });
    

    现在当你调用child.serialize(),它会返回这个对象:

    {
      child: {
        name: "Herbert",
        toys: [
          {
            name: 'Kazoo'
          }
        ]
      }
    }
    

    这是我需要的。这是 jsfiddle 的实际应用:http://jsfiddle.net/jgillick/LNXyp/8/

    【讨论】:

    • 使用 Ember 1.3.1/data 1.0.0-beta 6, property = Ember.get(record, key) 似乎返回一个空的承诺数组。这特别奇怪,因为我可以使用record.get('key').then(function(items){...}) 访问子记录。知道这是否是一个已知问题吗?
    猜你喜欢
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多