(ember-data API Rev 11用に更新されました...)
TL; DR
アソシエーションをオンデマンドでロードするために使用する正しい方法は何ですか?特に、子レコードをロードしたら、サーバーから親レコードを再ロードするとhasMany配列が空になるという事実にどのように対処しますか?親の配列に子レコードのIDを含めたくない(おそらく含めることができない)。または、私が見逃しているこれを行う別の方法はありますか?DS.Adapter.findAssociation(...)
DS.Adapter.findHasMany(...)
hasMany
hasMany
ちなみに、キーリンケージの/定義でどのオプションを渡す必要があるかについて混乱していますbelongsTo
(サイドロードされたデータやIDの配列がない場合は、マッピングを使用する必要がありますか?)。私の協会の定義にあります、あなたが正しい可能性が高いです。
ロングバージョン
DS.RESTAdapter
ember-dataをASP.NETWebAPIバックエンドに結び付けるための独自のサブクラスを作成しています(Entity Frameworkを使用)。これまでのところ順調ですが、アソシエーションを正しく機能させるのにかなりの時間がかかっています。
このポスターと同様に、ember-dataのフロントページには 、モデルに関連付けがあり、そのプロパティがある場合、ストアが子レコードのリクエストを発行すると書かれていることに気付きました。ページからの引用:hasMany
get
次のようにプロファイルをリクエストする場合:
author.get('profile');
…RESTアダプターはURL/profiles?author_id=1にリクエストを送信します。
これは、サイドローディングを行わず、IDの配列を含めない場合に発生することを意味します。これらのドキュメントはやや古くなっていることに気付きましたが、APIバージョン7または最近のバージョン9のいずれでも、これを実現できませんでした。ただし、バージョン9ではメソッドを見つけましたが、バージョン11ではfindAssociation
findHasMany
私が推測しているメソッドは、これを実現するために使用された可能性があり、現在使用しようとしています。
IDまたはサイドロードの配列を含めてみませんか?
私がこれをしたくない(そしておそらくできない)3つの主な理由:
少なくとも私が使用している単純な装飾ベースのアプローチでは、ASP.NETWebAPIを使用してこれらのいずれかを実行する方法は明らかではありません。そして、私は今、バックエンドのシンプルさと薄さを本当に気に入っています。EFとWebAPIを使用すると、各エンティティのほぼ完全な定型文になり、完了です。ODataフィルタリングのサポートも「無料」で利用できます。
私の子レコードは、多くの場合、高価なクエリ(たとえば、集計...メトリックのロールアップ)を介して生成されます。また、単一の親エンティティには、さまざまなクラスの子エンティティがあります。したがって、すべての子タイプのIDを取得することでさえコストがかかり、すべての子レコードを生成してサイドローディングすることは問題外です。
主キーが複合キーである子エンティティがあります。少なくともアソシエーションを処理するためではなく、ember-dataでサポート/可能でさえあるこの例を見たことがありません(たとえば、IDの配列をどのように実行しますか?)。クライアント側モデルで、複合キーを単一の文字列に強制する計算プロパティを作成したので、を使用してストアから単一のレコードを取得できますが、
find(...)
これが関連付けでどのように機能するかはわかりません。
使用しようとしていますfindAssociation
findHasMany
findAssociation
APIバージョン9(および以前のバージョンの一部ですがすべてではありませんか?) 11では、関連付けの子レコードを取得するメソッドを実装できる可能性があることがわかりました。これはほとんど機能しますが、体操が必要です。これが私の一般化された方法です:DS.Adapter.findAssociation
DS.Adapter.findHasMany
hasMany
findAssociation
findHasMany
findHasMany: function (store, record, relationship, ids) {
var adapter = this;
var root = this.rootForType(relationship.type);
var query = relationship.options.query(record);
var hits = store.findQuery(relationship.type, query);
hits.on('didLoad', function () {
// NOTE: This MUST happen in the callback, because findHasMany is in
// the execution path for record.get(relationship.key)!!! Otherwise causes
// infinite loop!!!
var arrMany = record.get(relationship.key);
if (hits.get('isLoaded')) {
arrMany.loadingRecordsCount = 1 + hits.get('length') + (typeof arrMany.loadingRecordsCount == "number" ? arrMany.loadingRecordsCount : 0);
hits.forEach(function (item, index, enumerable) {
arrMany.addToContent(item);
arrMany.loadedRecord();
});
arrMany.loadedRecord(); // weird, but this and the "1 +" above make sure isLoaded/didLoad fires even if there were zero results.
}
});
}
これを機能させるために、私のhasMany
定義query
では、子のリクエストでクエリ文字列のパラメータのハッシュを返すレコード上の関数であるオプション値を設定します。これはASP.NETWebAPIバックエンド用であるため、これはおそらくODataフィルターになります。例:
App.ParentEntity = DS.Model.extend({
...
children: DS.hasMany('App.ChildEntity', {
query: function (record) {
return {
"$filter": "ChildForeignKey eq '" + record.get('id') + "'"
};
}
})
});
ManyArray
秘訣の1つは、 usingにアイテムを追加しaddToContent(item)
て、親レコードが編集されたかのように「ダーティ」とマークされないようにすることです。もう1つは、最初に親レコードのJSONを取得するときにtrue
、関連付け名のキーの値を手動で設定する必要があることです(サーバーからのJSONにはキーがまったくありません)。すなわち:
var a = Ember.isArray(json) ? json : [json];
for (var i = 0; i < a.length; i++) {
type.eachAssociation(function (key) {
var meta = type.metaForProperty(key);
a[i][key] = true;
});
}
これはおかしなことに聞こえますが、これが理由です。の実装を見て、DS.Store.findMany
どこが呼び出されているかを見つけると、次のことがわかります。findAssociation
findHasMany
findMany: function(type, ids, record, relationship){
...
if (!Ember.isArray(ids)) {
var adapter = this.adapterForType(type);
if (adapter && adapter.findHasMany) { adapter.findHasMany(this, record, relationship, ids); }
else { throw fmt("Adapter is either null or does not implement `findMany` method", this); }
return this.createManyArray(type, Ember.A());
}
そして、が呼び出されたember-data内部関数からこの行を見ると、2番目のパラメーターに何が渡されているかがわかります。hasAssociation
hasRelationship
findMany
relationship = store.findMany(type, ids || [], this, meta);
したがって、呼び出される唯一の方法は、JSONの値を「真実」であるが、配列ではないものにすることです。私はを使用します。これはバグ/不完全であるか、私が間違った方向に進んでいることを示していると思います-誰かがそれも素晴らしいと私に言うことができれば。findAssociation
findHasMany
true
これで、ember-dataを取得して、子レコードのリクエストをサーバーに自動的に発行できます。たとえばhttp://myserver.net/api/child_entity/$filter=ChildForeignKey eq '42'
、子レコードが読み込まれ、親レコードに関連付けられます(ちなみに、逆のbelongsTo
関係)。明示的に触れていないにもかかわらず、適切に入力されます。どこで、どのように発生しているのかわかりません)。
しかし、私がそこで止まらなければ、それはかなりすぐに崩壊します。
親レコードのリロードの処理
つまり、子レコードを親レコードに正常にロードした後、すべての親レコードが取得される場所に移動するとします(メニューにデータを入力するため)。新しくロードされた親レコードにはIDの配列がなく、サイドロードも行われないため、親レコードは子なしで更新されます。さらに悪いことに、ManyArray
'sisLoaded
プロパティは残りtrue
ます!だから私は子供たちをリロードするために何も観察することさえできません。
したがって、子の値を表示するビューを同時に画面に表示すると、子のレコード値がないことにすぐになります。または、1つに戻ると、App.store.find('App.ParentEntity', 42)
が呼び出されたときに、サーバーへの要求なしでレコードがストアからロードされ、もちろん子レコードはありません。
これは、私がおそらくこれを間違った方法で行っているというヒント#2です。それで...オンデマンドで子レコードをロードする正しい方法は何ですか?
どうもありがとう!