模型也是一個(gè)類,它定義了向用戶展示的屬性和數(shù)據(jù)行為。模型的定義非常簡單,只需要繼承DS.Model類即可,或者你也可以直接使用Ember CLI命令創(chuàng)建。比如使用命令模型 ember g model person
定義了一個(gè)模型類person
。
// app/models/person.js
import DS from 'ember-data';
export default DS.Model.extend({
});
這個(gè)是個(gè)空的模型,沒有定義任何屬性。有了模型類你就可以使用find
方法查找數(shù)據(jù)了。
上面定義的模型類person
還沒有任何屬性,下面為這個(gè)類添加幾個(gè)屬性。
// app/models/person.js
import DS from 'ember-data';
export default DS.Model.extend({
firstName: DS.attr(),
lastName: DS.attr(),
birthday: DS.attr()
});
上述代碼定義了3個(gè)屬性,但是還未給屬性指定類型,默認(rèn)都是string
類型。這些屬性名與你連接的服務(wù)器上的數(shù)據(jù)key
是一致的。甚至你還可以在模型中定義計(jì)算屬性。
// app/models/person.js
import DS from 'ember-data';
export default DS.Model.extend({
firstName: DS.attr(),
lastName: DS.attr(),
birthday: DS.attr(),
fullName: Ember.computed('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
})
});
這段代碼在模型類中定義了一個(gè)計(jì)算屬性fullName
。
前面定義的模型類是沒有指定屬性類型的,默認(rèn)情況下都是string
類型,顯然這是不夠的,簡單的模型屬性類型包括:string
,number
,boolean
,date
。這幾個(gè)類型我想不用我解釋都應(yīng)該知道了。
不僅可以指定屬性類型,你還可以指定屬性的默認(rèn)值,在attr()方法的第二個(gè)參數(shù)指定。比如下面的代碼:
// app/models/person.js
import DS from 'ember-data';
export default DS.Model.extend({
username: DS.attr('string'),
email: DS.attr('string'),
verified: DS.attr('boolean', { defaultValue: false }), //指定默認(rèn)值是false
// 使用函數(shù)返回值作為默認(rèn)值
createAt: DS.attr('string', { defaultValue(){ return new Date(); } })
});
正如代碼注釋所述的,設(shè)置默認(rèn)值的方式包括直接指定或者是使用函數(shù)返回值指定。
Ember的模型也是有類似于數(shù)據(jù)庫的關(guān)聯(lián)關(guān)系的。只是相對(duì)于復(fù)制的數(shù)據(jù)庫Ember的模型就顯得簡單很多,其中包括一對(duì)一,一對(duì)多,多對(duì)多關(guān)聯(lián)關(guān)系。這種關(guān)系是與后臺(tái)的數(shù)據(jù)庫是相統(tǒng)一的。
聲明一對(duì)一關(guān)聯(lián)使用DS.belongsTo設(shè)置。比如下面的兩個(gè)模型。
// app/models/user.js
import DS from 'ember-data';
export default DS.Model.extend({
profile: DS.belongsTo(‘profile’);
});
// app/models/profile.js
import DS from ‘ember-data’;
export default DS.Model.extend({
user: DS.belongsTo(‘user’);
});
聲明一對(duì)多關(guān)聯(lián)使用DS.belongsTo(多的一方使用)和DS.hasMany(少的一方使用)設(shè)置。比如下面的兩個(gè)模型。
// app/models/post.js
import DS from ‘ember-data’;
export default DS.Model.extend({
comments: DS.hasMany(‘comment’);
});
這個(gè)模型是一的一方。下面的模型是多的一方;
// app/models/comment.js
import DS from ‘ember-data’;
export default DS.Model.extend({
post: DS.belongsTo(‘post’);
});
這種設(shè)置的方式與Java 的hibernate非常相似。
聲明一對(duì)多關(guān)聯(lián)使用DS.hasMany設(shè)置。比如下面的兩個(gè)模型。
// app/models/post.js
import DS from ‘ember-data’;
export default DS.Model.extend({
tags: DS.hasMany(‘tag’);
});
// app/model/tag.js
import DS from ‘ember-data’;
export default DS.Model.extend({
post: DS.hasMany(‘post’);
});
多對(duì)多的關(guān)系設(shè)置都是使用DS.hasMany,但是并不需要“中間表”,這個(gè)與數(shù)據(jù)的多對(duì)多有點(diǎn)不同,如果是數(shù)據(jù)的多對(duì)多通常是通過中間表關(guān)聯(lián)。
Ember Data會(huì)盡力去發(fā)現(xiàn)兩個(gè)模型之間的關(guān)聯(lián)關(guān)系,比如前面的一對(duì)多關(guān)系中,當(dāng)comment
發(fā)生變化的時(shí)候會(huì)自動(dòng)更新到post
,因?yàn)槊恳粋€(gè)comment
只對(duì)應(yīng)一個(gè)post
,可以有comment
確定到某個(gè)一個(gè)post
。
然而,有時(shí)候同一個(gè)模型中會(huì)有多個(gè)與此關(guān)聯(lián)模型。這時(shí)你可以在反向端用DS.hasMany的inverse
選項(xiàng)指定其關(guān)聯(lián)的模型:
// app/model/comment.js
import DS from 'ember-data';
export default DS.Model.extend({
onePost: DS.belongsTo(‘post’),
twoPost: DS.belongsTo(‘post’),
redPost: DS.belongsTo(‘post’),
bluePost: DS.belongsTo(‘post’)
});
在一個(gè)模型中同時(shí)與3個(gè)post
關(guān)聯(lián)了。
// app/models/post.js
import DS from ‘ember-data’;
export default DS.Model.extend({
comments: hasMany(‘comment’, { inverse: ‘redPost’ });
});
當(dāng)comment
發(fā)生變化時(shí)自動(dòng)更新到redPost
這個(gè)模型。
當(dāng)你想定義一個(gè)自反關(guān)系的模型時(shí)(模型本身的一對(duì)一關(guān)系),你必須要顯式使用inverse
指定關(guān)聯(lián)的模型。如果沒有逆向關(guān)系則把inverse
值設(shè)置為null
。
// app/models/folder.js
import DS from ‘ember-data’;
export default DS.Model.extend({
children: DS.hasMany(‘folder’, { reverse: ‘parent’ });
parent: DS.hasMany(‘folder’, { reverse: ‘children’ });
});
一個(gè)文件夾通常有父文件夾或者子文件夾。此時(shí)父文件夾和子文件夾與本身都是同一個(gè)類型的模型。此時(shí)你需要顯式使用inverse
屬性指定,比如這段代碼所示,“children……”這行代碼意思是這個(gè)模型有一個(gè)屬性children
,并且這個(gè)屬性也是一個(gè)folder
,模型本身作為父文件夾。同理“parent……”這行代碼的意思是這個(gè)模型有個(gè)屬性parent
,并且這個(gè)屬性也是一個(gè)folder
,模型本身是這個(gè)屬性的子文件夾。比如下圖結(jié)構(gòu):
這個(gè)有點(diǎn)像數(shù)據(jù)結(jié)構(gòu)中的鏈表。你可以把children
和parent
想象成是一個(gè)指針。
如果僅有關(guān)聯(lián)關(guān)系沒有逆向關(guān)系直接把inverse
設(shè)置為null
。
// app/models/folder.js
import DS from ‘ember-data’;
export default DS.Model.extend({
parent: DS.belongsTo(‘folder’, { inverse: null });
});
// app/models/user.js
import DS from ‘ember-data’;
export default DS.Model.extend({
bestFriend: DS.belongsTo(‘folder’, { inverse: ‘bestFriend’ });
});v
這個(gè)關(guān)系與數(shù)據(jù)庫設(shè)置設(shè)計(jì)中雙向一對(duì)一很類似。
有些模型可能會(huì)包含深層嵌套的數(shù)據(jù)對(duì)象,如果也是使用上述的關(guān)聯(lián)關(guān)系定義那么將是個(gè)噩夢!對(duì)于這種情況最好是把數(shù)據(jù)定義成簡單對(duì)象,雖然增加點(diǎn)冗余數(shù)據(jù)但是降低了層次。另外一種是把嵌套的數(shù)據(jù)定義成模型的屬性(也是增加冗余但是降低了嵌套層次)。
博文完整代碼放在Github(博文經(jīng)過多次修改,博文上的代碼與github代碼可能有出入,不過影響不大?。?,如果你覺得博文對(duì)你有點(diǎn)用,請(qǐng)?jiān)趃ithub項(xiàng)目上給我點(diǎn)個(gè)star
吧。您的肯定對(duì)我來說是最大的動(dòng)力??!
更多建議: