Ember Data学习笔记与总结归纳 (持续更新)

单耘豪
2023-12-01

Something about Ember Data

Introduction

Records

A record is an instance of a model that contains data loaded from a server. Your application can also create new records and save them back to the server.
A record is uniquely identified by its model type and ID.
An ID is usually assigned to a record by the server when you save it for the first time, but you can also generate IDs client-side.

Adapter

An adapter is an object that translates requests from Ember (such as “find the user with an ID of 1”) into requests to a server.
Whenever your app asks the store for a record that it doesn’t have cached, it will ask the adapter for it. If you change a record and save it, the store will hand the record to the adapter to send the appropriate data to your server and confirm that the save was successful.
Adapters let you completely change how your API is implemented without impacting your Ember application code.

Caching

In order to prevent this stale data from being a problem for long, Ember Data will automatically make a request in the background each time a cached record is returned from the store.

Defining Models

ember g model person
// models/person.js
import DS from "ember-data";

export default DS.Model.extend({
})

Defining Attributes

使用 DS.attr 来定义 model 实例的属性。当然也可以使用 计算属性 等方法来操作这些属性。

// models/person.js
import DS from "ember-data";
import {computed} from "@ember/object";

export default DS.Model.extend({
	firstname: DS.attr(),
	lastname: DS.attr(),
	fullname: computed("firstname","lastname",function(){
		retunrn  `${this.firstName} ${this.lastName}`;
	})
})

Transform

Ember Data allows you to define simple serialization and deserialization methods for attribute types called transforms.
You can specify that you would like a transform to run for an attribute by providing the transform name as the first argument to the DS.attr method. Ember Data supports attribute types of string, number, boolean, and date, which coerce the value to the JavaScript type that matches its name.

// models/person.js
import DS from "ember-data";

export default DS.Model.extend({
	name: DS.attr("string"),
	age: DS.attr("number"),
	admin: DS.attr("boolean"),
	birthday: DS.attr("date")
})

Transforms are not required. If you do not specify a transform name Ember Data will do no additional processing of the value.

Custom Transforms

可以自定义 transforms

$	ember g transform dollars

将美分与美元之间的转换:

// app/transforms/dollars.js
import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize(serialized) {
    return serialized / 100; // returns dollars
  },

  serialize(deserialized) {
    return deserialized * 100; // returns cents
  }
});

A transform has two functions: serialize and deserialize.
Deserialization converts a value to a format that the client expects.
Serialization does the reverse and converts a value to the format expected by the persistence layer.

使用:

//	app/models/product.js
import DS from 'ember-data';

export default DS.Model.extend({
  spent: DS.attr('dollars')
});

Options

DS.attr can also take a hash of options as a second parameter. At the moment the only option available is defaultValue, which can use a value or a function to set the default value of the attribute if one is not supplied.

//	app/models/user.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 }),
  createdAt: DS.attr('date', {
    defaultValue() { return new Date(); }
  })
});

Read-only Attributes

When the API returns a deeply nested, read-only object or array, there is no need to create multiple models with DS.attr('hasMany') or DS.attr('belongsTo') relationships. This could result in a potentially large amount of unnecessary code. You can access these objects in the template without transforming them. This can be done with DS.attr() (No attribute type).
The following example shows how to define these attributes without transforming them and accessing them within a template:

	location: DS.attr() // a read-only object
	tags: DS.attr() // a read-only array
	{{model.location.latitude}}

Finding Records

概述:
查询多个使用:

  • sotre.findAll()
  • store.peekAll()
  • store.query()

查询单个使用:

  • store.findRecord()
  • store.peekRecord()
  • 或者在store.query()的返回中取firstObject

返回DS.promiseArray的:

  • store.findAll()
  • store.findRecord()
  • store.query()

DS.promiseArrayfulfill状态时即为DS.RecordArray.DS.promiseArray不是普通的JS Array,如果取这其中的一项,需要使用objectAt(index). 下方是详细的解释。

Retrieving a Single Record

// GET /blog-posts/1
this.store.findRecord('blog-post', 1)  // => GET /blog-posts/1
  .then(function(blogPost) {
      // Do something with `blogPost`
  });
  • store.PeekRecord:
    Use store.peekRecord() to retrieve a record by its type and ID, without making a network request. This will return the record only if it is already present in the store:
let blogPost = this.store.peekRecord('blog-post', 1); // => no network request

Retrieving Multiple Records

Use store.findAll() to retrieve all of the records for a given type:

// GET /blog-posts
this.store.findAll('blog-post') // => GET /blog-posts
  .then(function(blogPosts) {
    // Do something with `blogPosts`
  });

Use store.peekAll() to retrieve all of the records for a given type that are already loaded into the store, without making a network request:

let blogPosts = this.store.peekAll('blog-post'); // => no network request

store.findAll() returns a DS.PromiseArray that fulfills to a DS.RecordArray and store.peekAll directly returns a DS.RecordArray.
It’s important to note that DS.RecordArray is not a JavaScript array, it’s an object that implements MutableArray. This is important because, for example, if you want to retrieve records by index, the [] notation will not work–you’ll have to use objectAt(index) instead.

Querying for Multiple Records

Ember Data provides the ability to query for records that meet certain criteria. Calling store.query() will make a GET request with the passed object serialized as query params. This method returns a DS.PromiseArray in the same way as findAll.

For example, we could search for all person models who have the name ofPeter:

// GET to /persons?filter[name]=Peter
this.store.query('person', {
  filter: {
    name: 'Peter'
  }
}).then(function(peters) {
  // Do something with `peters`
});

Creating, Updating and Deleting

Creating Record

createRecord():

store.createRecord('post', {
  title: 'Rails is Omakase',
  body: 'Lorem ipsum'
});
//	To create a new instance of a  `Post`  that has a relationship with a  `User`  record:

let user = this.store.peekRecord('user', 1);
store.createRecord('post', {
  title: 'Rails is omakase',
  user: user
});

controllersroute中使用。

Updating Records

和设置属性大致相同

this.store.findRecord('person', 1).then(function(tyrion) {
  // ...after the record has loaded
  tyrion.set('firstName', 'Yollo');
});

Persisting Records

如果有尚未保存的修改:
record.get('hasDirtyAttributes'); // true
使用来查看record 中的修改:

record.changedAttributes()

回滚修改:

record.rollbackAttributes();

其他包括save(),errorsdeleteRecord()deleteRecord() 等可以自行查看。

Relationships

One-to-One

两个model之间一对一的关系,使用DS.belongsTo:

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

One-to-Many

使用DS.belongsToDS.hasMany来声明两个model之间的一对多关系:

//	app/models/blog-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({
  blogPost: DS.belongsTo('blog-post')
});

Many-to-Many

使用DS.hasMany声明两个model之间的多对多关系:

//	app/models/blog-post.js
import DS from 'ember-data';

export default DS.Model.extend({
  tags: DS.hasMany('tag')
});
//	app/models/tag.js
import DS from 'ember-data';

export default DS.Model.extend({
  blogPosts: DS.hasMany('blog-post')
});

Written by Frank Wang.

 类似资料: