在Ember中建模双向对称关系

时间:2015-12-09 18:33:05

标签: ember.js ember-data

想象一下,我们有两个实体,存储在关系数据库中:

person(id, name)

friendship(id, personAID, personBID, strength)

在这里,我们可以看到两个人可以成为朋友,并且可以成为一个"力量" (一些数值)将给予这种友谊。 如果第1和第2人是朋友,那么我们在友谊表中有以下条目:

xyz | 1 | 2 | 50

请注意,以下相应条目不存在

abc | 2 | 1 | 50

每个"友谊"。

只创建一个条目

我挣扎的是如何在ember应用程序中对此进行建模。 A"人"可以有很多友谊,还有友谊和友谊。确切地说是2个人。

// models/person.js
DS.Model.extend({
    name: DS.attr('string'),
    friendships: DS.hasMany('friendship', {inverse: 'friends'})
});

友谊对象被序列化为

数组
{
    id: 'abc',
    friends: ['1', '2'],
    score: '50'
}

这样:

// models/friendship.js
DS.Model.extend({
    friends: DS.hasMany('person', {inverse: friendships}),
    personA: Ember.computed(friends, function() {
        return this.get('friends').objectAt('0');
    }),
    personB: Ember.computed(friends, function() {
        return this.get('friends').objectAt('1');
    }),
    getFriend: function(id) {
        if (id === this.get('personA.id')) {
            return this.get('personB');
        }
        if (id === this.get('personB.id')) {
            return this.get('personA');
        }
        return null;
    },
    score: DS.attr('number')
});

友谊模式的实施由于很多原因而感到沮丧。首先,友谊不会有很多"朋友。它有两个。但是,如果我将实现更改为:

DS.Model.extend({
    personA: DS.belongsTo('person'),
    personB: DS.belongsTo('person'),
    ...
});

然后我不确定如何建模" hasMany"人际关系=>友谊。 '逆转'例如,字段设置为?

"得分"领域正在变得复杂。如果那不存在,那么这将是“人”中的反身关系。 model,但该关系具有其他数据,必须能够表示为自己的实体。

另外,考虑到我想列出某个人的所有朋友的情况,以及该友谊的力量," getFriend()"功能是必需的。这个功能对我来说有点味道,我无法理解为什么。

所以我的问题是,你认为什么是一种有效的方法来模拟包含额外数据的双向对称关系,例如"得分"领域?我无法改变数据在数据库中的存储方式,但我确实可以控制其他所有内容,因此我可以将数据转换为数据库中的任何结构,然后转移到Ember客户端。 / p>

Ember和Ember-data 2.x

1 个答案:

答案 0 :(得分:4)

所以我花了一年时间,但我终于回到了这个问题,我认为我有一个相当不错的解决方案。我实际上写了两篇博文,详细介绍了解决方案(part 1part 2),但是让我试着在这里总结一下。

该解决方案具有前端和后端组件。

我定义了模型(在Rails中,但它可能是真的),如下所示:

colorbar

我使用JSON API compliant backend和名为jsonapi-resources的gem来帮助我实现服务器响应。无论您的实施方式如何,重要的一点是为每个人提供一个返回该人友谊的终点(例如import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec import matplotlib.colors as mcolors gs = gridspec.GridSpec(2, 1, height_ratios=[1, 4] ) ax = [plt.subplot(g) for g in gs] parameterToColorBy = np.linspace(5, 10, 6, dtype=float) def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=-1): if n == -1: n = cmap.N new_cmap = mcolors.LinearSegmentedColormap.from_list( 'trunc({name},{a:.2f},{b:.2f})'.format(name=cmap.name, a=minval, b=maxval), cmap(np.linspace(minval, maxval, n))) return new_cmap minColor = 0.00 maxColor = 0.85 inferno_t = truncate_colormap(plt.get_cmap("inferno"), minColor, maxColor) colors = [inferno_t(i) for i in np.linspace(0, 1, parameterToColorBy.shape[0])] norm = mpl.colors.Normalize(parameterToColorBy[0], parameterToColorBy[-1]) cb = mpl.colorbar.ColorbarBase(ax[0], cmap=inferno_t, norm=norm, ticks=parameterToColorBy, orientation='horizontal') ax[0].xaxis.set_ticks_position('top') for p, c in zip(parameterToColorBy, colors): ax[1].plot(np.arange(2)/p, c=c) plt.show() )。

该端点应返回可以获取数据的关系链接,以查看人员在关系的两侧是谁:

# app/models/friendship.rb
class Friendship < ActiveRecord::Base
  belongs_to :friender, class_name: Person
  belongs_to :friended, class_name: Person
end

# app/models/person.rb
class Person < ActiveRecord::Base
  def friendships
    Friendship.where("friender_id = ? OR friended_id = ?", id, id);
  end
end

Ember侧的模型如下所示:

/people/1/friendships

在路线中,我正在抓住这个人,并以最简单的方式展示他们的友谊:

{
  "data": [
    {
      "id": "1",
      "type": "friendships",
      (...)
      "attributes": {
        "strength": 3
      },
      "relationships": {
        "friender": {
          "links": {
            "self": "http://localhost:4200/friendships/1/relationships/friender",
            "related": "http://localhost:4200/friendships/1/friender"
          },
          "data": {
            "type": "people",
            "id": "1"
          }
        },
        "friended": {
          "links": {
            "self": "http://localhost:4200/friendships/1/relationships/friended",
            "related": "http://localhost:4200/friendships/1/friended"
          },
          "data": {
            "type": "people",
            "id": "4"
          }
        }
      }
    },
    {
      "id": "2",
      "type": "friendships",
      (...)
    }
  ]
}

这样可行,但会向后端发送大量xhr请求,每个结束一个(friender和friended)的关系。

您可以在友谊关卡的响应中使用resource linkage来减少这些请求的数量。如果您不使用JSON API,肯定有方法可以指示哪条记录位于关系的末尾(friendship.friender或friendship.friended),这样就不需要再进行ajax请求来获取它们。