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