Ember数据操作 #
一、创建记录 #
1.1 createRecord #
javascript
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
export default class PostsNewController extends Controller {
@service store;
@action
createPost() {
const post = this.store.createRecord('post', {
title: 'New Post',
body: 'Content...',
});
}
}
1.2 保存记录 #
javascript
@action
async savePost() {
const post = this.store.createRecord('post', {
title: 'New Post',
body: 'Content...',
});
try {
await post.save();
console.log('保存成功');
} catch (error) {
console.error('保存失败:', error);
}
}
1.3 创建并关联 #
javascript
@action
async createComment(post) {
const comment = this.store.createRecord('comment', {
body: 'Great post!',
post: post,
});
await comment.save();
}
二、读取记录 #
2.1 findAll #
获取所有记录:
javascript
// app/routes/posts.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class PostsRoute extends Route {
@service store;
model() {
return this.store.findAll('post');
}
}
2.2 findRecord #
获取单个记录:
javascript
// app/routes/posts/show.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class PostsShowRoute extends Route {
@service store;
model(params) {
return this.store.findRecord('post', params.post_id);
}
}
2.3 query #
条件查询:
javascript
model() {
return this.store.query('post', {
category: 'tech',
status: 'published',
page: 1,
limit: 10,
});
}
2.4 queryRecord #
查询单个记录:
javascript
model() {
return this.store.queryRecord('post', {
slug: 'hello-world',
});
}
2.5 peekAll / peekRecord #
从缓存读取(不发请求):
javascript
// 获取所有已加载记录
const posts = this.store.peekAll('post');
// 获取单个已加载记录
const post = this.store.peekRecord('post', 1);
三、更新记录 #
3.1 基本更新 #
javascript
@action
async updatePost(post) {
post.title = 'Updated Title';
await post.save();
}
3.2 更新多个属性 #
javascript
@action
async updatePost(post, attrs) {
post.setProperties(attrs);
await post.save();
}
3.3 更新关联 #
javascript
@action
async changeAuthor(post, newAuthor) {
post.author = newAuthor;
await post.save();
}
3.4 部分更新 #
javascript
@action
async updateTitle(post, newTitle) {
post.title = newTitle;
await post.save({ adapterOptions: { partial: true } });
}
四、删除记录 #
4.1 destroyRecord #
删除并持久化:
javascript
@action
async deletePost(post) {
await post.destroyRecord();
}
4.2 deleteRecord #
仅标记删除(不持久化):
javascript
@action
markForDeletion(post) {
post.deleteRecord();
// 需要调用 save() 才会持久化
}
4.3 unloadRecord #
从Store移除(不持久化):
javascript
@action
removeFromCache(post) {
post.unloadRecord();
}
五、记录状态 #
5.1 检查状态 #
javascript
// 新记录
post.isNew; // true/false
// 已保存
post.isSaved; // true/false
// 有未保存更改
post.hasDirtyAttributes; // true/false
// 正在保存
post.isSaving; // true/false
// 已删除
post.isDeleted; // true/false
// 正在删除
post.isDeleting; // true/false
// 有效
post.isValid; // true/false
// 有错误
post.hasErrors; // true/false
5.2 changedAttributes #
javascript
const changes = post.changedAttributes();
// { title: ['Old Title', 'New Title'] }
5.3 rollbackAttributes #
javascript
@action
cancelChanges(post) {
post.rollbackAttributes();
}
六、批量操作 #
6.1 批量创建 #
javascript
@action
async createMultiple() {
const posts = [
{ title: 'Post 1', body: '...' },
{ title: 'Post 2', body: '...' },
{ title: 'Post 3', body: '...' },
];
const records = posts.map((data) => this.store.createRecord('post', data));
await Promise.all(records.map((post) => post.save()));
}
6.2 批量更新 #
javascript
@action
async publishAll(posts) {
posts.forEach((post) => {
post.isPublished = true;
});
await Promise.all(posts.map((post) => post.save()));
}
6.3 批量删除 #
javascript
@action
async deleteAll(posts) {
await Promise.all(posts.map((post) => post.destroyRecord()));
}
七、错误处理 #
7.1 基本错误处理 #
javascript
@action
async savePost(post) {
try {
await post.save();
} catch (error) {
console.error('保存失败:', error);
// 检查错误
if (post.errors.length > 0) {
post.errors.forEach((error) => {
console.log(`${error.attribute}: ${error.message}`);
});
}
}
}
7.2 验证错误 #
javascript
@action
async saveWithValidation(post) {
try {
await post.save();
} catch (error) {
if (error.errors) {
error.errors.forEach((err) => {
console.log(`字段 ${err.source.pointer} ${err.detail}`);
});
}
}
}
7.3 网络错误 #
javascript
@action
async saveWithRetry(post, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
await post.save();
return;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
}
八、关联操作 #
8.1 添加关联 #
javascript
@action
async addComment(post) {
const comment = this.store.createRecord('comment', {
body: 'New comment',
post: post,
});
await comment.save();
}
8.2 移除关联 #
javascript
@action
async removeComment(comment) {
comment.post = null;
await comment.save();
}
8.3 更新多对多 #
javascript
@action
async addTag(post, tag) {
post.tags.pushObject(tag);
await post.save();
}
@action
async removeTag(post, tag) {
post.tags.removeObject(tag);
await post.save();
}
九、缓存控制 #
9.1 强制重载 #
javascript
model(params) {
return this.store.findRecord('post', params.post_id, {
reload: true,
});
}
9.2 后台重载 #
javascript
model(params) {
return this.store.findRecord('post', params.post_id, {
backgroundReload: true,
});
}
9.3 预加载关联 #
javascript
model(params) {
return this.store.findRecord('post', params.post_id, {
include: 'author,comments',
});
}
十、最佳实践 #
10.1 在路由中加载数据 #
javascript
// 好的做法
export default class PostsRoute extends Route {
model() {
return this.store.findAll('post');
}
}
// 避免 - 在组件中加载数据
10.2 使用async/await #
javascript
// 好的做法
async savePost(post) {
await post.save();
this.router.transitionTo('posts.show', post.id);
}
// 避免 - Promise链
savePost(post) {
post.save().then(() => {
this.router.transitionTo('posts.show', post.id);
});
}
10.3 处理加载状态 #
handlebars
{{#if @post.isSaving}}
<span>保存中...</span>
{{else}}
<button {{on "click" (fn this.save @post)}}>保存</button>
{{/if}}
十一、总结 #
数据操作要点:
| 操作 | 方法 |
|---|---|
| 创建 | createRecord() + save() |
| 读取 | findAll(), findRecord(), query() |
| 更新 | 修改属性 + save() |
| 删除 | destroyRecord() |
| 缓存 | peekAll(), peekRecord() |
掌握数据操作是构建应用的核心技能。
最后更新:2026-03-28