更新
请注意,这个问题适用于 Ember Data pre-1.0 beta,通过 URL 加载关系的机制在 1.0 beta 后发生了显着变化!
前段时间我问了一个更长的问题,但由于库从那时起发生了变化,我会问一个更简单的版本:
你怎么用DS.Adapter.findHasMany
?我正在构建一个适配器,我希望能够get
在关系属性上加载关系的内容,这看起来像是这样做的方式。但是,查看 Ember Data 代码,我看不出如何调用此函数(如果需要,我可以在注释中解释)。
我的后端没有一种简单的方法可以在我发送的 JSON 中的属性键中包含一个 id 数组——我正在使用的序列化程序不允许我挂钩任何可以改变它的地方,而且它也将是计算成本高。
曾几何时,Ember Data 的首页显示了一个执行此“延迟加载”的示例……这可能吗,或者路线图上列出的“处理部分加载的记录”,目前还不能完成.?
截至 1 月 15 日,我正在使用 API 修订版 11,主分支。
更新
好的,以下主要工作。findHasMany
首先,根据测试用例的实现,我在适配器中创建了以下方法:
findHasMany: function(store, record, relationship, details) {
var type = relationship.type;
var root = this.rootForType(type);
var url = (typeof(details) == 'string' || details instanceof String) ? details : this.buildURL(root);
this.ajax(url, "GET", {
success: function(json) {
var serializer = this.get('serializer');
var pluralRoot = serializer.pluralize(root);
var hashes = json[pluralRoot]; //FIXME: Should call some serializer method to get this?
store.loadMany(type, hashes);
// add ids to record...
var ids = [];
var len = hashes.length;
for(var i = 0; i < len; i++){
ids.push(serializer.extractId(type, hashes[i]));
}
store.loadHasMany(record, relationship.key, ids);
}
});
}
上述的先决条件是您的序列化程序中必须有一个运行良好的方法,但在大多数情况下extractId
,内置的方法可能会做。RESTAdapter
这行得通,但有一个重大问题,我还没有真正解决过这种延迟加载方法的任何尝试:如果从服务器重新加载原始记录,一切都会失败。显示这一点的最简单用例是,如果您加载单个记录,然后检索hasMany
,然后再加载所有父记录。例如:
var p = App.Post.find(1);
var comments = p.get('comments');
// ...later...
App.Post.find();
在仅上述代码的情况下,发生的情况是,当 Ember Data 重新实现记录时,它识别出记录上已经存在一个值 ( posts/1
),尝试重新填充它,并遵循不同的代码路径来处理JSON 哈希中的 URL 字符串作为单字符 ID 的数组。具体来说,它将 JSON 中的值传递给Ember.EnumerableUtils.map
,这可以理解地将字符串的字符枚举为数组成员。
因此,我尝试通过“修补”来解决这个DS.Model.hasManyDidChange
问题,发生这种情况的地方,如下所示:
// Need this function for transplanted hasManyDidChange function...
var map = Ember.EnumerableUtils.map;
DS.Model.reopen({
});
(^ 没关系,这是一个非常糟糕的主意。)
更新 2
当从服务器重新加载父模型时,我发现我必须(至少)再做一件事来解决上述问题。URL 被拆分为单个字符的代码路径位于DS.Model.reloadHasManys
. 所以,我用下面的代码覆盖了这个方法:
DS.Model.reopen({
reloadHasManys: function() {
var relationships = get(this.constructor, 'relationshipsByName');
this.updateRecordArraysLater();
relationships.forEach(function(name, relationship) {
if (relationship.kind === 'hasMany') {
// BEGIN FIX FOR OPAQUE HASMANY DATA
var cachedValue = this.cacheFor(relationship.key);
var idsOrReferencesOrOpaque = this._data.hasMany[relationship.key] || [];
if(cachedValue && !Ember.isArray(idsOrReferencesOrOpaque)){
var adapter = this.store.adapterForType(relationship.type);
var reloadBehavior = relationship.options.reloadBehavior;
relationship.name = relationship.name || relationship.key; // workaround bug in DS.Model.clearHasMany()?
if (adapter && adapter.findHasMany) {
switch (reloadBehavior) {
case 'ignore':
//FIXME: Should probably replace this._data with references/ids, currently has a string!
break;
case 'force':
case 'reset':
default:
this.clearHasMany(relationship);
cachedValue.set('isLoaded', false);
if (reloadBehavior == 'force' || Ember.meta(this).watching[relationship.key]) {
// reload the data now...
adapter.findHasMany(this.store, this, relationship, idsOrReferencesOrOpaque);
} else {
// force getter code to rerun next time the property is accessed...
delete Ember.meta(this).cache[relationship.key];
}
break;
}
} else if (idsOrReferencesOrOpaque !== undefined) {
Ember.assert("You tried to load many records but you have no adapter (for " + type + ")", adapter);
Ember.assert("You tried to load many records but your adapter does not implement `findHasMany`", adapter.findHasMany);
}
} else {
this.hasManyDidChange(relationship.key);
}
//- this.hasManyDidChange(relationship.key);
// END FIX FOR OPAQUE HASMANY DATA
}
}, this);
}
});
加上这一点,使用基于 URL 的 hasManys几乎是可用的,但还有两个主要问题:
首先,反向belongsTo
关系不能正常工作——你必须将它们全部删除。这似乎是使用 ArrayProxies 完成 RecordArrays 的方式的问题,但它很复杂。当父记录被重新加载时,两个关系都被处理为“删除”,所以当循环遍历数组时,belongsTo 解关联代码同时从数组中删除项目,然后循环因为它试图访问而崩溃不再存在的索引。这个我还没想好,太难了。
其次,它通常效率低下——我最终过于频繁地从服务器重新加载 hasMany ......但至少我可以通过在服务器端发送一些缓存头来解决这个问题。
任何尝试使用此问题中的解决方案的人,我建议您将上面的代码添加到您的应用程序中,它最终可能会让您到达某个地方。但我认为,这确实需要在 Ember Data 中修复才能正常工作。
我希望这最终会得到更好的支持。一方面,他们所采用的JSONAPI方向明确表示这种事情是规范的一部分。但另一方面,Ember Data 0.13(或 rev 12?)更改了默认的序列化格式,因此如果您想这样做,您的 URL 必须位于名为...的 JSON 属性中*_ids
......例如child_object_ids
......在这种情况下您要发送的 ID!这似乎表明不使用 ID 数组在他们的用例列表中并不高。任何阅读此内容的 Ember Data 开发人员:请支持此功能!
欢迎对此提出进一步的想法!