S'p*_*'Kr 10 ember.js ember-data
请注意,此问题适用于Ember Data pre-1.0 beta,通过URL加载关系的机制在1.0 beta之后发生了显着变化!
我回过头问了一个更长的问题,但自从那时候图书馆发生了变化,我会问一个更简单的版本:
你怎么用的DS.Adapter.findHasMany
?我正在构建一个适配器,我希望能够加载get
关系属性的关系内容,这看起来像是这样做的方式.但是,看看Ember数据代码,我看不出如何调用这个函数(如果需要,我可以在评论中解释).
我的后端没有一种简单的方法可以在我发送的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);
}
});
}
Run Code Online (Sandbox Code Playgroud)
上面的先决条件是你必须extractId
在序列化程序中有一个良好的工作方法,但RESTAdapter
在大多数情况下,内置的方法可能会.
这是有效的,但有一个重要的问题,我在这种懒惰加载方法的任何尝试中还没有真正得到:如果原始记录从服务器重新加载,一切都进入底池.显示这一点的最简单的用例是,如果您加载单个记录,然后检索hasMany
,然后加载所有父记录.例如:
var p = App.Post.find(1);
var comments = p.get('comments');
// ...later...
App.Post.find();
Run Code Online (Sandbox Code Playgroud)
仅在上面的代码的情况下,当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({
});
Run Code Online (Sandbox Code Playgroud)
(^没关系,这是一个非常糟糕的主意.)
当我从服务器重新加载父模型时,我发现我必须做(至少)一件事来解决上面提到的问题.将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);
}
});
Run Code Online (Sandbox Code Playgroud)
通过这种添加,使用基于URL的hasManys 几乎可用,还有两个主要问题:
首先,反向belongsTo
关系无法正常工作 - 您必须将它们全部删除.这似乎是使用ArrayProxies完成RecordArrays的方式的一个问题,但它很复杂.当父记录被重新加载时,两个关系都被处理为"删除",所以当循环遍历数组时,belongsTo解除关联代码同时从数组中删除项目,然后循环因为尝试访问而变得怪异一个不再存在的索引.我还没想出这个,这很难.
其次,它通常是低效的 - 我最终经常从服务器重新加载hasMany ......但至少我可以通过在服务器端发送一些缓存头来解决这个问题.
任何人都试图在这个问题中使用这些解决方案,我建议你将上面的代码添加到你的应用程序中,它最终会让你到达某个地方.但我认为这真的需要在Ember Data中修复才能正常工作.
我希望最终得到更好的支持.一方面,他们明确指出的JSONAPI方向说这种事情是规范的一部分.但另一方面,Ember Data 0.13(或rev 12?)改变了默认的序列化格式,因此如果你想这样做,你的URL必须在一个叫做的JSON属性中*_ids
...例如child_object_ids
...当它不均匀时你在这种情况下发送的身份证!这似乎表明,在用例列表中不使用ID数组并不高.任何Ember Data开发者都会这样说:请支持这个功能!
欢迎进一步思考!
有效负载需要包含数组以外的“其他内容”,而不是 ID 数组。
对于 RESTAdapter,返回的 JSON 如下所示:
{blog: {id: 1, comments: [1, 2, 3]}
Run Code Online (Sandbox Code Playgroud)
如果你想手动/以不同的方式处理关联,你可以返回一个像这样的 JSON:
{blog: {id: 1, comments: "/posts/1/comments"}
Run Code Online (Sandbox Code Playgroud)
然后由您的适配器从指定的 URL 获取数据。
归档时间: |
|
查看次数: |
3787 次 |
最近记录: |