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.
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.
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.
ember g model person
// models/person.js
import DS from "ember-data";
export default DS.Model.extend({
})
使用 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}`;
})
})
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 theDS.attr
method. Ember Data supports attribute types ofstring
,number
,boolean
, anddate
, 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.
可以自定义 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
anddeserialize
.
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')
});
DS.attr
can also take a hash of options as a second parameter. At the moment the only option available isdefaultValue
, 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(); }
})
});
When the API returns a deeply nested, read-only object or array, there is no need to create multiple models with
DS.attr('hasMany')
orDS.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 withDS.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}}
概述:
查询多个使用:
sotre.findAll()
store.peekAll()
store.query()
查询单个使用:
store.findRecord()
store.peekRecord()
store.query()
的返回中取firstObject
返回DS.promiseArray
的:
store.findAll()
store.findRecord()
store.query()
当DS.promiseArray
到fulfill
状态时即为DS.RecordArray
.DS.promiseArray
不是普通的JS Array,如果取这其中的一项,需要使用objectAt(index)
. 下方是详细的解释。
store.findRecord()
to retrieve a record by its type and ID. This will return a promise that fulfills with the requested record:// GET /blog-posts/1
this.store.findRecord('blog-post', 1) // => GET /blog-posts/1
.then(function(blogPost) {
// Do something with `blogPost`
});
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
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.
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`
});
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
});
在controllers
和route
中使用。
和设置属性大致相同
this.store.findRecord('person', 1).then(function(tyrion) {
// ...after the record has loaded
tyrion.set('firstName', 'Yollo');
});
如果有尚未保存的修改:
record.get('hasDirtyAttributes'); // true
使用来查看record
中的修改:
record.changedAttributes()
回滚修改:
record.rollbackAttributes();
其他包括save()
,errors
,deleteRecord()
,deleteRecord()
等可以自行查看。
两个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')
});
使用DS.belongsTo
与 DS.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')
});
使用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.