Ember 定義模型

2018-01-06 17:59 更新

模型也是一個(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ù)了。

1,定義屬性

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

2,指定屬性類型與默認(rèn)值

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

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

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

1,一對(duì)一

聲明一對(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’);
});

2,一對(duì)多

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

3,多對(duì)多

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

4,顯式反轉(zhuǎ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.hasManyinverse選項(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è)模型。

5,自反關(guān)系

1,一對(duì)多

當(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):

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

這個(gè)有點(diǎn)像數(shù)據(jù)結(jié)構(gòu)中的鏈表。你可以把childrenparent想象成是一個(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 });
});

2,一對(duì)一

//  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ì)一很類似。

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

有些模型可能會(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)力??!

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)