Ember 定義模型

2018-01-06 17:59 更新

模型也是一個類,它定義了向用戶展示的屬性和數(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ù)了。

1,定義屬性

上面定義的模型類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

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

前面定義的模型類是沒有指定屬性類型的,默認情況下都是string類型,顯然這是不夠的,簡單的模型屬性類型包括:string,numberboolean,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ù)返回值指定。

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è)置。比如下面的兩個模型。

//  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’);
});

2,一對多

聲明一對多關(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非常相似。

3,多對多

聲明一對多關(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)。

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)的模型:

//  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這個模型。

5,自反關(guān)系

1,一對多

當你想定義一個自反關(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):

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

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

如果僅有關(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 });
});

2,一對一

//  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è)計中雙向一對一很類似。

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

公眾號
微信公眾號

編程獅公眾號