get
根据 ID 获取实体。
方法签名
get(id: EntityIdType): Observable<InstanceType<T>>
示例
基础用法
import { firstValueFrom } from 'rxjs';
const todo = await firstValueFrom(Todo.get('591e97aa-f7e3-499c-9fa4-4e2ae4459ef6'));
console.log(todo.title);
响应式订阅
const subscription = Todo.get(todoId).subscribe(todo => {
console.log(todo.title);
});
subscription.unsubscribe();
批量获取
// 批量获取多个实体
const todoIds = ['id-1', 'id-2', 'id-3'];
const todos = await Promise.all(todoIds.map(id => firstValueFrom(Todo.get(id))));
结合错误处理
import { catchError, of } from 'rxjs';
const todo$ = Todo.get(todoId).pipe(
catchError(error => {
console.error('获取 todo 失败:', error);
return of(null);
})
);
get vs findOne
| 方法 | 查询方式 | 性能 | 参数 | 返回值 |
|---|---|---|---|---|
get | 主键索引 | 最快 | 仅需要 ID | Observable<T> |
findOne | 条件查询 | 较慢 | 复杂查询条件 | Observable<T | undefined> |
// get - 适合已知 ID 的情况
const todo1 = await firstValueFrom(Todo.get('todo-id'));
// findOne - 适合需要条件查询的情况
const todo2 = await firstValueFrom(
Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'userId', operator: '=', value: 'user-123' },
{ field: 'completed', operator: '=', value: false }
]
}
})
);
性能优化
1. 使用 get 而非 findOne
当你已经知道实体的 ID 时,始终优先使用 get 而不是 findOne:
// ✅ 好:直接通过 ID 获取
Todo.get(todoId);
// ❌ 不必要的复杂:使用 findOne 查询 ID
Todo.findOne({
where: {
combinator: 'and',
rules: [{ field: 'id', operator: '=', value: todoId }]
}
});
2. 缓存策略
实体获取后会被缓存,重复调用 get 时会直接返回缓存的实体引用:
// 第一次调用会从数据库读取
const todo1 = await firstValueFrom(Todo.get(todoId));
// 第二次调用会返回相同的实体引用
const todo2 = await firstValueFrom(Todo.get(todoId));
console.log(todo1 === todo2); // true - 相同的对象引用
3. 响应式更新
使用 Observable 订阅,当实体更新时自动收到通知:
const subscription = Todo.get(todoId).subscribe(todo => {
console.log('Todo 更新了:', todo);
});
// 在其他地方更新这个 todo
await Todo.update(todo, { completed: true });
// 上面的订阅会自动收到更新后的 todo
错误处理
ID 不存在时的处理
import { catchError, EMPTY } from 'rxjs';
// 方式 1: 使用 catchError 捕获错误
const todo$ = Todo.get(todoId).pipe(
catchError(error => {
if (error.code === 'ENTITY_NOT_FOUND') {
console.log('Todo 不存在');
return EMPTY;
}
throw error;
})
);
// 方式 2: 使用 try-catch
try {
const todo = await firstValueFrom(Todo.get(todoId));
} catch (error) {
console.error('获取失败:', error);
}
常见用例
1. 路由参数获取实体
import { ActivatedRoute } from '@angular/router';
import { switchMap } from 'rxjs';
@Component({
selector: 'app-todo-detail'
})
export class TodoDetailComponent {
todo$ = this.route.params.pipe(switchMap(params => Todo.get(params['id'])));
constructor(private route: ActivatedRoute) {}
}
2. 实时数据同步
// 订阅实体变化,实现实时更新
const todoSubscription = Todo.get(todoId).subscribe(todo => {
// 每当这个 todo 在数据库中被更新时
// 这里会自动收到最新的数据
updateUI(todo);
});
3. 预加载相关数据
// 获取 todo 并预加载相关的用户信息
const todoWithUser$ = Todo.get(todoId).pipe(
switchMap(todo => User.get(todo.userId).pipe(map(user => ({ todo, user }))))
);
最佳实践
- 优先使用 get:当有 ID 时,始终使用
get而不是findOne - 利用缓存:理解实体缓存机制,避免不必要的重复查询
- 响应式编程:使用 Observable 订阅而非 Promise,享受自动更新的好处
- 错误处理:始终处理实体不存在的情况
- 类型安全:利用 TypeScript 类型推断,避免类型错误
参考
- findOne - 根据条件查找单个实体
- findOneOrFail - 查找单个实体,找不到抛出错误
- find - 查询多个实体