9

我很难在 ember 数据中保存一对多的关系。我有这样的关系:

App.ParameterSet = DS.Model
    name: DS.attr("string")
    regions: DS.hasMany("App.Region")

App.Region = DS.Model
    name: DS.attr("string")

如果我要做这样的事情:

parameterSet = App.ParameterSet.find(5)
@transaction = @get("store").transaction()
@transaction.add(parameterSet)
region1 = App.Region.find(10)
region2 = App.Region.find(11)
parameterSet.set("name", "foo")
parameterSet.get("regions").pushObject(region)
@transaction.commit()

然后我想看到一个带有这样有效负载的 PUT 请求:

api/ParameterSets/5

{parameterSet: {name: "foo", regionIds:[10, 11]}}

但相反,我得到了这个:

{parameterSet: {name: "foo"}}

我不关心从孩子到父母的关系,但如果我添加parameterSet: DS.belongsTo("App.ParameterSet")到 App.Region 模型,那么我会收到两个 PUT 请求到两个新关系的区域 url,这不是我真正想要的。

我想这是一个多对多的关系,我不确定它是否得到支持,但是关于如何实现我所描述的任何想法?谢谢

4

2 回答 2

8

关系的序列化hasMany由 的addHasMany()方法处理json_serializer.js

源代码中包含以下注释:

默认的 REST 语义是仅在嵌入的情况下添加具有-多关系。如果关系最初是由 ID 加载的,我们假设这是作为性能优化完成的,并且对 has-many 的更改应保存为子关系的外键更改。

要实现您想要的,一种选择是指示应将关系嵌入到您的适配器中。

App.Store = DS.Store.extend({
  adapter: DS.RESTAdapter.extend({
    serializer: DS.RESTSerializer.extend({
      init: function() {
        this._super();
        this.map('App.ParameterSet', {
          regions: { embedded: 'always' }
        });
      }
    })
  })
});

当然,现在您的后端将需要在参数集的 JSON 中实际嵌入关联区域的 JSON。如果您想保持原样,您可以简单地addHasMany()使用自定义序列化覆盖。

App.Store = DS.Store.extend({
  adapter: DS.RESTAdapter.extend({
    serializer: DS.RESTSerializer.extend({
      addHasMany: function(hash, record, key, relationship) {
        // custom ...
      }
    })
  })
});
于 2013-02-28T21:16:34.747 回答
2

我无法为 ahmacleod 的答案添加评论,但除了我注意到在修改子记录时父记录没有被标记为脏之外,它是正确的。在问题的示例中,不会出现问题,因为名称也在父记录上被修改。

但是,一般来说,如果您要遵循 ahmacleod 的第二个答案,则需要覆盖 RESTAdapter 上的方法dirtyRecordsForHasManyChange。否则,序列化程序中的 addHasMany 永远不会被调用,因为该记录甚至没有被标记为脏。

现有方法如下所示:

dirtyRecordsForHasManyChange: function(dirtySet, record, relationship) {
  var embeddedType = get(this, 'serializer').embeddedType(record.constructor, relationship.secondRecordName);

  if (embeddedType === 'always') {
    relationship.childReference.parent = relationship.parentReference;
    this._dirtyTree(dirtySet, record);
  }
},

所以我想你会想要这样的东西:

App.Store = DS.Store.extend({
  adapter: DS.RESTAdapter.extend({
    dirtyRecordsForHasManyChange: function(dirtySet, record, relationship) {
      relationship.childReference.parent = relationship.parentReference;
      this._dirtyTree(dirtySet, record);
    },

    serializer: DS.RESTSerializer.extend({
      addHasMany: function(hash, record, key, relationship) {
        // custom ...
      }
    })
  })
});
于 2013-06-16T15:44:07.933 回答