Ember 定義模型

2018-01-06 17:59 更新

模型也是一個類,它定義了向用戶展示的屬性和數(shù)據(jù)行為。模型的定義非常簡單,只需要繼承DS.Model類即可,或者你也可以直接使用Ember CLI命令創(chuàng)建。比如使用命令模型 ember g model person定義了一個模型類person

  1. // app/models/person.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. });

這個是個空的模型,沒有定義任何屬性。有了模型類你就可以使用find方法查找數(shù)據(jù)了。

1,定義屬性

上面定義的模型類person還沒有任何屬性,下面為這個類添加幾個屬性。

  1. // app/models/person.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. firstName: DS.attr(),
  5. lastName: DS.attr(),
  6. birthday: DS.attr()
  7. });

上述代碼定義了3個屬性,但是還未給屬性指定類型,默認都是string類型。這些屬性名與你連接的服務(wù)器上的數(shù)據(jù)key是一致的。甚至你還可以在模型中定義計算屬性。

  1. // app/models/person.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. firstName: DS.attr(),
  5. lastName: DS.attr(),
  6. birthday: DS.attr(),
  7. fullName: Ember.computed('firstName', 'lastName', function() {
  8. return `${this.get('firstName')} ${this.get('lastName')}`;
  9. })
  10. });

這段代碼在模型類中定義了一個計算屬性fullName

2,指定屬性類型與默認值

前面定義的模型類是沒有指定屬性類型的,默認情況下都是string類型,顯然這是不夠的,簡單的模型屬性類型包括:string,numberboolean,date。這幾個類型我想不用我解釋都應(yīng)該知道了。

不僅可以指定屬性類型,你還可以指定屬性的默認值,在attr()方法的第二個參數(shù)指定。比如下面的代碼:

  1. // app/models/person.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. username: DS.attr('string'),
  5. email: DS.attr('string'),
  6. verified: DS.attr('boolean', { defaultValue: false }), //指定默認值是false
  7. // 使用函數(shù)返回值作為默認值
  8. createAt: DS.attr('string', { defaultValue(){ return new Date(); } })
  9. });

正如代碼注釋所述的,設(shè)置默認值的方式包括直接指定或者是使用函數(shù)返回值指定。

3,定義模型的關(guān)聯(lián)關(guān)系

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)一的。

1,一對一

聲明一對一關(guān)聯(lián)使用DS.belongsTo設(shè)置。比如下面的兩個模型。

  1. // app/models/user.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. profile: DS.belongsTo(‘profile’);
  5. });
  1. // app/models/profile.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. user: DS.belongsTo(‘user’);
  5. });

2,一對多

聲明一對多關(guān)聯(lián)使用DS.belongsTo(多的一方使用)和DS.hasMany(少的一方使用)設(shè)置。比如下面的兩個模型。

  1. // app/models/post.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. comments: DS.hasMany(‘comment’);
  5. });

這個模型是一的一方。下面的模型是多的一方;

  1. // app/models/comment.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. post: DS.belongsTo(‘post’);
  5. });

這種設(shè)置的方式與Java 的hibernate非常相似。

3,多對多

聲明一對多關(guān)聯(lián)使用DS.hasMany設(shè)置。比如下面的兩個模型。

  1. // app/models/post.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. tags: DS.hasMany(‘tag’);
  5. });
  1. // app/model/tag.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. post: DS.hasMany(‘post’);
  5. });

多對多的關(guān)系設(shè)置都是使用DS.hasMany,但是并不需要“中間表”,這個與數(shù)據(jù)的多對多有點不同,如果是數(shù)據(jù)的多對多通常是通過中間表關(guān)聯(lián)。

4,顯式反轉(zhuǎ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.hasManyinverse選項指定其關(guān)聯(lián)的模型:

  1. // app/model/comment.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. onePost: DS.belongsTo(‘post’),
  5. twoPost: DS.belongsTo(‘post’),
  6. redPost: DS.belongsTo(‘post’),
  7. bluePost: DS.belongsTo(‘post’)
  8. });

在一個模型中同時與3個post關(guān)聯(lián)了。

  1. // app/models/post.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. comments: hasMany(‘comment’, { inverse: redPost });
  5. });

comment發(fā)生變化時自動更新到redPost這個模型。

5,自反關(guān)系

1,一對多

當你想定義一個自反關(guān)系的模型時(模型本身的一對一關(guān)系),你必須要顯式使用inverse指定關(guān)聯(lián)的模型。如果沒有逆向關(guān)系則把inverse值設(shè)置為null

  1. // app/models/folder.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. children: DS.hasMany(‘folder’, { reverse: parent });
  5. parent: DS.hasMany(‘folder’, { reverse: children });
  6. });

一個文件夾通常有父文件夾或者子文件夾。此時父文件夾和子文件夾與本身都是同一個類型的模型。此時你需要顯式使用inverse屬性指定,比如這段代碼所示,“children……”這行代碼意思是這個模型有一個屬性children,并且這個屬性也是一個folder,模型本身作為父文件夾。同理“parent……”這行代碼的意思是這個模型有個屬性parent,并且這個屬性也是一個folder,模型本身是這個屬性的子文件夾。比如下圖結(jié)構(gòu):

結(jié)構(gòu)圖

這個有點像數(shù)據(jù)結(jié)構(gòu)中的鏈表。你可以把childrenparent想象成是一個指針。

如果僅有關(guān)聯(lián)關(guān)系沒有逆向關(guān)系直接把inverse設(shè)置為null。

  1. // app/models/folder.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. parent: DS.belongsTo(‘folder’, { inverse: null });
  5. });

2,一對一

  1. // app/models/user.js
  2. import DS from ember-data’;
  3. export default DS.Model.extend({
  4. bestFriend: DS.belongsTo(‘folder’, { inverse: bestFriend });
  5. });v

這個關(guān)系與數(shù)據(jù)庫設(shè)置設(shè)計中雙向一對一很類似。

6,嵌套數(shù)據(jù)

有些模型可能會包含深層嵌套的數(shù)據(jù)對象,如果也是使用上述的關(guān)聯(lián)關(guān)系定義那么將是個噩夢!對于這種情況最好是把數(shù)據(jù)定義成簡單對象,雖然增加點冗余數(shù)據(jù)但是降低了層次。另外一種是把嵌套的數(shù)據(jù)定義成模型的屬性(也是增加冗余但是降低了嵌套層次)。
博文完整代碼放在Github(博文經(jīng)過多次修改,博文上的代碼與github代碼可能有出入,不過影響不大?。绻阌X得博文對你有點用,請在github項目上給我點個star吧。您的肯定對我來說是最大的動力?。?/p>

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號