我的三个模型之间有以下对象关系(我不使用Backbone-relational ...这只是描述我的数据的底层结构):
Person has many Cars
Car has many Appraisals.
我有一个方法来检索一个人,这个方法带来了所有汽车和那些汽车的评估。它看起来像这样:
{id: 1,
name: John Doe,
cars: [
{id: 3, make: 'Porsche',
appraisals: [
{id: 27, amount: '45000', date: '01/01/2011'}
]
},
{id: 4, make: 'Buick', appraisals: []}
]
}
当我创建一个新人时,我会传递这个混乱。在我的Person的initialize
函数中,我这样做:
...
initialize: function() {
//Cars => Collection of Car
this.cars = new Cars();
_.each(this.get('cars'), function(car) {
this.cars.add(new Car(car));
});
this.unset('cars');
}
...
在我的Car initialize
函数中,我做了类似的事情:
...
initialize: function() {
//Appraisals => Collection of Appraisal
this.appraisals = new Appraisals();
_.each(this.get('appraisals'), function(appraisal) {
this.appraisals.add(new Appraisal(appraisal));
});
this.unset('appraisals');
}
...
我还必须覆盖Person和Car模型的toJSON函数。
这有什么问题吗?我已经看到它在其他地方建议制作嵌套集合属性而不是属性,我的经验证实这更容易,但我想知道我是在打破一些规则还是做一些愚蠢的事情。
答案 0 :(得分:4)
我没有“将嵌套集合存储为属性或属性”的答案,但我认为您可以简化代码初始化嵌套集合,如下所示:
人:
...
initialize: function() {
this.cars = new Cars(this.get('cars'));
this.unset('cars');
}
...
汽车:
...
initialize: function() {
this.appraisals = new Appraisals(this.get('appraisals'));
this.unset('appraisals');
}
...
答案 1 :(得分:3)
我在这里回答了类似的问题:backbone.js - getting extra data along with the request
在我提供的答案中,更多的是关于拥有模型关联的集合 - 基本上有一个。
我认为一个人应该有一个包含汽车模型的CarsList。汽车应该有一个包含评估模型的AppraisalsList。您可能会根据需要覆盖Person和Car的parse和toJSON函数。
我肯定会避免使用关联属性。上面例子中未设置的功能给我带来了难闻的气味。
答案 2 :(得分:1)
如果我可以给出2美分的投入:
如果您要绘制类的OOD类图并使用您选择的任何面向对象语言(除了javascript之外)对关联建模,您将如何做?
你看到backbone.js有助于将'结构'放到你的javascript中,这可能会成为纠结的意大利面条代码。因此,如果你的人有很多汽车,而汽车有很多评估你有两个选择:组合与协会
组成:您在上面做的事情:人物对象负责创建汽车和汽车对象以创建评估。每个对象的“生命周期”取决于父对象。现在可能/可能不是它应该如何建模,但这是你做出的选择。
现在,让我们看看简单的关联。您可以独立创建人员,汽车和评估(如果没有汽车,可能不会存在评估,但现在让我们假设其他情况)。
现在创建了这些对象,但是你需要“连接”这些关联 - 你可以在一个单独的“初始化器”类/容器中进行外部操作,可以这么说,只需使用setter / getters即可连接它们。
结论:使用最适合您的域的模型,不要让它受数据存储(即本例中的JSON对象)的约束。 Backbone的纯粹之美来自于这种能力,可以在编码时为您的代码赋予经典的OO结构并以这种方式思考。因此,选择OO关系(组合,聚合或简单关联)的良好组合,并为您的问题选择“最佳模型”并相应地实施。
结合@ kulesa的建议,您将“清理”您的代码并实现您想要的目标,而无需担心在有效组织代码时违反任何原则/做法。
希望这有帮助!
答案 3 :(得分:1)
我个人认为使用属性来存储某些模型的数据是不合理的。你有什么经历使得属性变得更容易?
Backbone在内部似乎只对元数据使用属性(例如集合中模型的by-id和by-cid映射)并快速访问属性(例如id
属性,该属性已更新每当id
属性发生变化时)。使用属性也会阻止您使用Backbone的事件系统或.get()
/ .set()
,并强制您覆盖.toJSON()
。
坚持使用属性,我相信你可以通过覆盖.set()
来获得相同的结果 - 在.initialize()
之前创建模型的新实例时会调用它,并且它也会被调用如果其他东西试图设置任何属性。我曾经做过类似的事情:
var Person = Backbone.Model.extend({
set: function(attributes, options){
var outAttributes = {};
_.each(attributes, function(value, name){
switch(name){
case 'cars':
outAttributes.cars = new Cars(value);
break;
default:
outAttributes[name] = value;
}
}, this);
Backbone.Model.prototype.set.call(this, outAttributes, options);
}
});
...您可以将其修改为更新现有的Cars实例,而不是创建新实例。
.set()
也是Backbone更新id
属性值的地方,因此如果您选择使用属性而不是属性,那么吸入值可能仍然是最好的(而不是{ {1}})。
答案 4 :(得分:0)
我有类似的情况,我这样解决了:
parse: function(data) {
if (data.Success) {
var policies = Rens.get('Policies').model, // model with nested collextion
claims = Rens.get('Claims').model; // model with nested collextion
// reseting collections
claims.claims.reset();
policies.policies.reset();
$(data.Result.Policies).each(function(i, policy) {
var claimsList = policy.ClaimsList,
policyWithClaims = _.clone(policy);
claims.claims.add(claimsList);
_.extend(policyWithClaims, {
ClaimsList: claims.getPolicyClaims.bind({
context: claims,
policyNumber: policy.PolicyNumber
}),
CarYearString: Rens.formatDate(policy.CarYear).date.HH,
PolicyEndDateString: Rens.formatDate(policy.PolicyEndDate).fullDate
});
policies.policies.add(policyWithClaims);
});
}
}
在此之后,我收集了策略,每个策略都具有链接到声明集合的方法的属性。
claims.getPolicyClaims
会返回当前政策的所有声明