我最近遇到了Backbone和RequireJS的问题,因为我们有一个相当复杂的数据模型,我需要表示它,这导致了循环依赖和自引用的问题。我在网上读了很多帖子(没有一篇真的有效),但我想我已经找到了解决方案。因此,我想分享这一点,希望它能帮助经历过这个问题的人,但也要问你们,你们是否认为有办法把事情收拾好。
第一个问题是,我有一些引用集合的模型,这些模型引用了引用集合的模式,所有这些都创建了一个混乱的循环依赖关系。坦率地说,这只是破坏了应用程序。下面是一个伪代码示例:
Model A
has Collection B
Collection B
of Model B
Model B
has Collection A
has Collection C
Collection A
of Model A
Collection C
of Model C
Backbone文档指出,这可以通过以下方式实现:
initialize: function() {
this.messages = new Messages;
this.messages.url = '/mailbox/' + this.id + '/messages';
this.messages.on("reset", this.updateCounts);
},
我尝试了各种方法来满足我们的需求,但我们复杂的嵌套需求打破了Backbone。因此,我偶然发现了主干关系,并创建了数据模型的基本工作表示(这涉及到创建一个垫片来使用RequireJS)。从本质上讲,这是有效的。所以我扩展了这个例子,使模型C也可以有集合C的实例(自引用)。这似乎再次奏效。杰出的然而,将该示例应用于我的应用程序更为困难——事实证明,将模型和集合拆分为单独的文件更为困难,因为主干关系希望集合和模型名称位于全局命名空间上(Require和"use strict"有点棘手)。由于我们的数据模型很复杂,我想使用字符串标识符来表示关系,以进行前向引用,而不是显式的需求引用,事实证明这也很困难。我尝试将所有内容添加到exports命名空间,但再次失败。无论如何,我认为我已经找到了一个解决方案,将集合和模型添加到一个自定义名称空间,然后将该名称空间添加到backlinerelational模型范围。我把我的自定义库命名为"奥卡"(因为虎鲸确实很棒)。
bootstrap.js
require.config({
paths: {
"jquery" : "../bower_components/jquery/jquery",
"underscore" : "../bower_components/underscore-amd/underscore",
"backbone" : "../bower_components/backbone-amd/backbone",
"relational" : "../bower_components/backbone-relational/backbone-relational",
...
shim: {
"underscore": {
exports: "_"
},
"backbone": {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
"relational": {
deps: ["backbone"]
},
...
app.js
define(["backbone", "relational", "libs/orca", "collections/a", "models/a", "collections/b", "models/b", "collections/c", "models/c"], function(Backbone, Relational, Orca){
"use strict";
var App = function(options) {
this.initialize(otions);
};
App.prototype = _.extend(Backbone.Events, {
initialize: function(options) {
Orca.initialize();
var a = new Orca.Relational.ModelA([],{});
}
}
return App;
});
lib/orca.js
define(["backbone", "relational"], function(Backbone) {
"use strict";
var Orca = {
Relational: {},
initialize: function() {
Backbone.Relational.store.addModelScope(this.Relational);
}
};
// I actually extend Backbone.RelationalModel so I can have custom methods,
// e.g. "parse" but I've simplified the code for example's sake...
Orca.Model = Backbone.RelationalModel;
Orca.Collection = Backbone.Collection;
return Orca;
});
集合/a.js
define(["backbone", "libs/orca"], function(Backbone, Orca) {
"use strict";
Orca.Relational.CollectionA = Backbone.Collection.extend({});
});
型号/a.js
define(["backbone", "libs/orca"], function(Backbone, Orca) {
"use strict";
Orca.Relational.ModelA = Orca.Model.extend({
relations: [
{
type: Backbone.HasMany,
key: "bs",
relatedModel: "ModelB",
includeInJSON: Backbone.Model.prototype.idAttribute,
collectionType: "CollectionB",
reverseRelation: {
key: "a"
}
}
]
});
});
CollectionB和ModelB是相似的,所以为了简洁起见,我省略了它们。
展示自我参照:
define(["backbone", "libs/orca"], function(Backbone, Orca) {
"use strict";
Orca.Relational.ModelC = Orca.Model.extend({
relations: [
{
type: Backbone.HasMany,
key: "cs",
relatedModel: "ModelC",
includeInJSON: Backbone.Model.prototype.idAttribute,
collectionType: "CollectionC",
reverseRelation: {
key: "c"
}
}
]
});
});
因此,我对这段代码的错误在于,我在app.js中创建了一个ModelA的新实例。但是,因为它引用了CollectionB,而CollectionB又被ModelB使用,ModelB又引用了CollectionC并使用了ModelC,所以我必须将所有这些作为必需的依赖项来引用。有更好的方法吗?
我实际上已经停止使用Backbone Relational,现在我使用JJRelational,因为它允许多对多的关系。我还通过创建一个名为"relational.js"的新文件来引用集合和模型,并将它们作为对象的属性返回,从而消除了从主应用程序文件中引用集合和建模的需要。这样,如果我需要一个新的模型或集合,我只需要使用"relational.js"。
我的relational.js文件看起来有点像:
define([
// Models
"models/broadcast",
"models/version",
// Collections
"collections/broadcasts",
"collections/versions"
], function(
// Models
Broadcast,
Version,
// Collections
Broadcasts,
Versions
) {
"use strict";
var _relational = {
Broadcast: Broadcast,
Version: Version,
Broadcasts: Broadcasts,
Versions: Versions,
};
// Register the Collections
Backbone.JJRelational.registerCollectionTypes({
"Broadcasts": _relational.Broadcasts,
"Versions": _relational.Versions
});
// Provide JJRelational with model scope - pull request submitted to JJRelational to handle this
Backbone.JJStore.addModelScope(_relational);
return _relational;
});
然后在我的主应用程序.js:中
define(["libs/relational"], function(Relational){
var broadcast = new Relational.Broadcast();
});
您曾经提到过骨干协会吗。我建议你看一次。
当我使用它时,我也遇到过类似的循环依赖和自引用问题。原因是我已经将客户端的Models
映射到后端的Beans
,后者使用Hibernate
映射到Tables
。在Hibernate
中指定one-to-many
关系时,需要指定一个实体对另一个实体的引用,反之亦然。然后,当Jersey服务返回这些实体时,到JSON的转换具有循环依赖关系。我可以在后端使用一些注释来消除它。但在CCD_ 7方面没有办法解决。我向Backbone Associations
的作者提出了这个问题,他们解决了这个问题
希望这在某种程度上有所帮助。