基于@angular-ru/ngxs的一对多关联实体状态管理架构咨询
存储架构设计方案
核心设计思路
摒弃嵌套字典的状态结构,按实体类型拆分独立状态,所有实体统一使用@angular-ru/ngxs/entity提供的标准实体能力,通过applicationId外键做关联映射,既可以直接复用内置的addOne/removeOne/updateOne等操作方法,也能快速适配20+关联API的扩展需求。
各实体状态定义示例
@angular-ru/ngxs的实体模块内置了标准的实体状态结构与操作适配器,无需手动封装字典类型:
import { Injectable } from '@angular/core'; import { State } from '@ngxs/store'; import { EntityState, EntityStateModel } from '@angular-ru/ngxs/entity'; // 1. 主应用实体定义 export interface Application { id: string; name: string; // 其他字段 } export interface ApplicationStateModel extends EntityStateModel<Application> {} @State<ApplicationStateModel>({ name: 'applications', defaults: { ids: [], entities: {} } }) @Injectable() export class ApplicationState extends EntityState<Application> {} // 2. 提交记录实体定义,新增applicationId作为关联外键 export interface Commit { id: string; contributorName: string; applicationId: string; // 其他字段 } export interface CommitsStateModel extends EntityStateModel<Commit> {} @State<CommitsStateModel>({ name: 'commits', defaults: { ids: [], entities: {} } }) @Injectable() export class CommitsState extends EntityState<Commit> {} // 3. 日志实体定义,同理新增关联外键 export interface Log { id: string; format: string; applicationId: string; // 其他字段 } export interface LogsStateModel extends EntityStateModel<Log> {} @State<LogsStateModel>({ name: 'logs', defaults: { ids: [], entities: {} } }) @Injectable() export class LogsState extends EntityState<Log> {}
实体操作示例
所有增删改操作直接调用内置方法,无需手动写展开运算符更新状态:
import { Injectable } from '@angular/core'; @Injectable() export class AppDataService { constructor( private commitsState: CommitsState, private logsState: LogsState ) {} // 批量新增某应用的提交记录 saveAppCommits(appId: string, commits: Commit[]) { // 内置方法自动处理ids、entities的更新 this.commitsState.addAll(commits); } // 新增单条日志 addSingleLog(log: Log) { this.logsState.addOne(log); } // 删除单条提交记录 deleteCommit(commitId: string) { this.commitsState.removeOne(commitId); } }
按应用ID查询数据的选择器实现
通过外键过滤即可快速获取指定应用的关联数据:
import { createSelector } from '@ngxs/store'; // 提交记录选择器 export class CommitsSelectors { static getByAppId(appId: string) { return createSelector([CommitsState], (state: CommitsStateModel) => { return state.ids .map(id => state.entities[id]) .filter(commit => commit.applicationId === appId); }); } } // 组件中使用 @Component({ /* 组件配置 */ }) export class AppDetailComponent { // 直接订阅指定应用的提交记录 @Select(CommitsSelectors.getByAppId('当前应用ID')) appCommits$: Observable<Commit[]>; }
20+关联API的扩展方案
- 每个新的关联API对应的数据实体单独定义一个实体状态,统一继承
EntityState基类,所有增删改逻辑直接复用内置方法,无需重复编写状态更新代码 - 所有关联实体统一添加
applicationId外键,通用选择器逻辑可以封装为公共方法,无需为每个实体单独写过滤逻辑 - 状态全量扁平化,无嵌套结构,后续排查问题、做数据持久化都更易处理
内容的提问来源于stack exchange,提问作者Gaultier Romon
相关产品推荐
相关产品推荐

