EntityStatus<T>
Defined in: packages/rxdb/src/entity/entity-status.ts:37
实体状态管理器
职责:
- 状态跟踪:local/remote/modified/removed 标记实体的生命周期状态
- 变更记录:记录实体的所有变更历史(patches),支持撤销/重做
- 关系管理:维护实体间的关系缓存,处理级联操作
- 变更通知:通过 RxJS Subject 发布实体变更事件
架构设计:
- 使用 Proxy 拦截属性修改,自动记录变更
- 关系缓存由 EntityRelationCache 子模块管理(含多对多 Junction 延迟删除)
- 懒加载缓存(patch/fingerprint),按需计算避免性能浪费
Type Parameters
| Type Parameter | Description |
|---|---|
T extends EntityType | 实体类型 |
Implements
IEntityStatus<T>
Properties
_fingerprint?
protected optional _fingerprint?: string;
Defined in: packages/rxdb/src/entity/entity-status.ts:124
实体指纹 用于唯一标识实体的版本
_local
protected _local: boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:92
标识实体是否存在于本地数据库
_modified
protected _modified: boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:97
标识实体是否已被修改
_origin
protected _origin: InstanceType<T>;
Defined in: packages/rxdb/src/entity/entity-status.ts:118
实体原始数据 用于比较变更和恢复
_patch_cache?
protected optional _patch_cache?: Partial<InstanceType<T>>;
Defined in: packages/rxdb/src/entity/entity-status.ts:112
实体变更缓存
_patches
protected _patches: EntityPatch<T>[];
Defined in: packages/rxdb/src/entity/entity-status.ts:107
实体变更记录数组
_remote
protected _remote: boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:87
标识实体是否存在于远程数据库
_removed
protected _removed: boolean = false;
Defined in: packages/rxdb/src/entity/entity-status.ts:102
标识实体是否已被删除
patches$
readonly patches$: Observable<EntityPatch<T>[]>;
Defined in: packages/rxdb/src/entity/entity-status.ts:141
实体变更记录的可观察流 用于订阅实体变更
proxyTarget
readonly proxyTarget: InstanceType<T>;
Defined in: packages/rxdb/src/entity/entity-status.ts:135
实体代理对象 用于拦截并记录对象的属性访问和修改
rxdb
readonly rxdb: RxDB;
Defined in: packages/rxdb/src/entity/entity-status.ts:305
RxDB 实例
target
readonly target: InstanceType<T>;
Defined in: packages/rxdb/src/entity/entity-status.ts:129
实体原始对象
Implementation of
IEntityStatus.target
Accessors
fingerprint
Get Signature
get fingerprint(): string;
Defined in: packages/rxdb/src/entity/entity-status.ts:287
实体指纹(标识同一个引用的内容版本)
格式:${id}@${updatedAt.getTime()}@${内容修订号}
用途:
- 判断同一个实体引用的内容是否已被改动(
QueryTask.#next据此决定要不要发射) - 缓存键生成
- 冲突检测
Remarks
第三段是 EntityStatus 实例内部的内容修订号:可见值真的被改动过才 +1
(本地编辑、reset 撤销掉真实差异、replace/mergeExternal 写入了不同的值);
纯派生缓存失效(invalidateCache、保存完成的 modified = false、写回同样的值)不推进。
加它是因为前两段不够:
外部增量回填不保证带 updatedAt(notifyExternalUpdate 的 patch 可以只有业务字段,
QueryManager 还会专门丢掉「只有 updatedAt」的 patch),于是「值变了但 updatedAt 没变」
在旧格式下算不出差异,活查询永远停在旧值上。
因此本指纹只能沿时间轴比较同一个引用:修订号是实例内计数,不同 EntityStatus
实例之间不可比 —— 两个刚水合的引用都是 0,但各自改过之后的号码没有可比性。
「两个引用是不是同一行的同一版本」请比 id + updatedAt,不要比整串指纹。
懒加载:首次访问时生成并缓存;读取本身不推进修订号。
Returns
string
generation
Get Signature
get generation(): number;
Defined in: packages/rxdb/src/entity/entity-status.ts:249
当前代数,每次 reset()/replace() 递增一次。 供 proxy.ts 判断某次防抖排队的 checkChange 是否已经过期,见 #generation 声明处注释。
Returns
number
inversePatch
Get Signature
get inversePatch(): Partial<InstanceType<T>>;
Defined in: packages/rxdb/src/entity/entity-status.ts:234
逆向变更内容(用于撤销操作) 返回 origin 中对应 patch 的属性值
例如:patch = { name: 'new' } → inversePatch = { name: 'old' }
注意:返回 {} 表示"无真实变更",不返回 null。
Returns
Partial<InstanceType<T>>
local
Get Signature
get local(): boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:187
是否是本地数据
Returns
boolean
Set Signature
set local(value): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:190
是否在本地
Parameters
| Parameter | Type |
|---|---|
value | boolean |
Returns
void
Implementation of
IEntityStatus.local
modified
Get Signature
get modified(): boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:147
实体是否已修改 标记实体属性是否发生过变更(与 origin 对比)
Returns
boolean
Set Signature
set modified(value): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:159
设置修改状态 清理缓存确保下次访问 patch/fingerprint 时重新计算
不推进内容修订号:这条路看着像「本地编辑入口」,实际上适配器把查询算出来的
computed 列写回共享缓存实体走的也是它(m[prop] = value → proxy set → 这里)。
在这里推进会让树查询把自己的回填看成「结果变了」而再发一次 —— 自激。
Parameters
| Parameter | Type |
|---|---|
value | boolean |
Returns
void
Implementation of
IEntityStatus.modified
origin
Get Signature
get origin(): InstanceType<T>;
Defined in: packages/rxdb/src/entity/entity-status.ts:259
Returns
InstanceType<T>
Set Signature
set origin(value): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:256
设置原始值
Parameters
| Parameter | Type |
|---|---|
value | InstanceType<T> |
Returns
void
patch
Get Signature
get patch(): Partial<InstanceType<T>>;
Defined in: packages/rxdb/src/entity/entity-status.ts:212
当前变更内容(相对于 origin) 返回与 origin 不同的属性集合,用于生成数据库更新语句
优化:只比较被修改过的属性键,避免全量遍历
比较用 isEqual 深比较,与 Proxy set 拦截(proxy.ts)保持同一套相等语义。
必须深比较:适配器保存成功后会用 structuredClone 回填 origin,
引用比较会让 Date / json / 数组列永久残留假 diff,导致每次 UPDATE 重复写回。
边界(继承自 isEqual):自定义了 toString() 的值按 toString() 结果判等,
不看字段。若某列存的是这类对象(URL / Error / 领域值对象),两个 toString()
相同但字段不同的实例会被判为「没变」→ 该键不进 patch → 静默丢写。
这类列请存可序列化的普通对象,或自行在赋值前 normalize。
注意:返回 {} 表示"无真实变更"(与 origin 相等),不返回 null。
类型签名取消 | null,与运行时行为对齐。
Returns
Partial<InstanceType<T>>
patches
Get Signature
get patches(): EntityPatch<T>[];
Defined in: packages/rxdb/src/entity/entity-status.ts:241
获取变化
Returns
EntityPatch<T>[]
Implementation of
IEntityStatus.patches
remote
Get Signature
get remote(): boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:177
是否是远程数据
Returns
boolean
Set Signature
set remote(value): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:180
是否在远程
Parameters
| Parameter | Type |
|---|---|
value | boolean |
Returns
void
Implementation of
IEntityStatus.remote
removed
Get Signature
get removed(): boolean;
Defined in: packages/rxdb/src/entity/entity-status.ts:167
是否已删除
Returns
boolean
Set Signature
set removed(value): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:170
Parameters
| Parameter | Type |
|---|---|
value | boolean |
Returns
void
Methods
addRelationEntity()
addRelationEntity(relation, entity): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:558
委托给 EntityRelationCache.add — 见 relation-cache.ts
Parameters
| Parameter | Type |
|---|---|
relation | EntityRelationMetadata |
entity | any |
Returns
void
applyExternal()
applyExternal(data): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:450
应用一份外部数据,并按实体当前是否有未保存编辑自动选择合并策略。
Parameters
| Parameter | Type | Description |
|---|---|---|
data | Partial<InstanceType<T>> | 外部数据(整行回填或增量 patch 均可) |
Returns
void
Remarks
这是「外部数据落到已缓存实体」的唯一策略入口:
modified === false:走 replace,整行覆盖并重设基线;modified === true:走 mergeExternal,基线前移但逐字段避让本地编辑。
拆出这个方法而不是让各调用点自己判,是因为漏判的后果是静默的:直接 replace 一个脏实体
会把用户尚未保存的编辑写进 _origin 并把 _modified 归零,patch 随之清空 —— UI 看起来
没变,下一次 save() 却是 no-op,编辑永久丢失且全程无报错。查询结果回填、跨 tab 事件、
远端活查询整批回填三条路径都会命中缓存实体,任一处漏判都会复现同一个 bug。
本方法不做时效性判断。调用方若可能收到迟到的事件,需先用 isStaleEventPayload 拦截。
checkChange()
checkChange(recordAt?): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:472
记录实体变更
机制:
- 计算当前 patch 和 inversePatch
- 将变更记录追加到 patches 数组
- 通过 Subject 发布变更事件
时间戳说明:
- recordAt: 业务时间(Date),用于显示和排序
- timeStamp: 性能时间(performance.now),用于高精度计时和排序
Parameters
| Parameter | Type | Description |
|---|---|---|
recordAt | Date | 变更记录时间,默认当前时间 |
Returns
void
cleanRelationEntity()
cleanRelationEntity(relation): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:568
委托给 EntityRelationCache.clean — 见 relation-cache.ts
Parameters
| Parameter | Type |
|---|---|
relation | EntityRelationMetadata |
Returns
void
getNeedRemoveEntities()
getNeedRemoveEntities(): object[];
Defined in: packages/rxdb/src/entity/entity-status.ts:533
获取需要删除的实体列表
删除策略:
- 多对多关系:删除 Junction 实体(中间表记录)
- 其他关系:不自动删除关联实体(由业务层决定)
Junction 实体处理:
- removeRelationEntity 时加入 #remove_junction_set
- 保存时统一删除(保证事务一致性)
- 只删除 local=true 的(未保存的无需删除)
设计理由:
- ONE_TO_MANY/MANY_TO_ONE 的级联删除由数据库外键约束处理
- MANY_TO_MANY 没有直接的外键,需要应用层删除 Junction
Returns
object[]
待删除的 Junction 实体数组
getNeedSaveEntities()
getNeedSaveEntities(): InstanceType<T>[];
Defined in: packages/rxdb/src/entity/entity-status.ts:503
获取需要保存的实体列表
逻辑:
- 始终包含当前实体(this.proxyTarget)
- 遍历所有关系类型的缓存
- 筛选出 modified=true 的关联实体
注意:
- 此方法只查找直接关联的实体,不递归
- 递归查找由 entity.utils.ts 的 getNeedSaveEntities 处理
- 返回的实体需要进一步过滤(根据依赖顺序排序)
Returns
InstanceType<T>[]
需要保存的实体数组(包含自身和修改过的关联实体)
getRelationCache()
getRelationCache(relation): Set<any>;
Defined in: packages/rxdb/src/entity/entity-status.ts:573
委托给 EntityRelationCache.get — 见 relation-cache.ts
Parameters
| Parameter | Type |
|---|---|
relation | EntityRelationMetadata |
Returns
Set<any>
getRelationObservableEntry()
getRelationObservableEntry(relation): RelationObservableEntry | undefined;
Defined in: packages/rxdb/src/entity/entity-status.ts:578
委托给 EntityRelationCache.getObservableEntry — 见 relation-cache.ts
Parameters
| Parameter | Type |
|---|---|
relation | EntityRelationMetadata |
Returns
RelationObservableEntry | undefined
invalidateCache()
invalidateCache(): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:587
Returns
void
markChanged()
markChanged(key): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:330
记录属性变更 在 Proxy set 拦截时调用,同步记录哪些属性被修改
Parameters
| Parameter | Type | Description |
|---|---|---|
key | keyof InstanceType<T> | 被修改的属性键 |
Returns
void
markContentChanged()
markContentChanged(): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:604
声明「实体的可见内容刚被外部事件改动过」,推进内容修订号(fingerprint 第三段)。
这是唯一推进修订号的入口,且刻意只有一个调用方:QueryManager 把外部事件负载
物化进缓存实体的那一步。所有改值的方法(replace、mergeExternal、
proxy set → modified = true)都不推进,因为它们同时是查询自己回填结果的路径:
适配器把 SQL 算出来的 computed 列(hasChildren/level/…)写回共享缓存实体走的正是
这几条,在它们内部推进会让查询把自己的回填看成「结果变了」而再发一次 —— 自激。
「这次写入来自外部事件」这个信息只有调用方知道,所以判断留给调用方; 调用方同样有责任先确认可见值真的变了 —— 无条件调用会导致多余发射。
Returns
void
mergeExternal()
mergeExternal(data): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:408
应用外部更新,但逐字段避让本地未保存的编辑。
Parameters
| Parameter | Type | Description |
|---|---|---|
data | Partial<InstanceType<T>> | 外部事件负载(增量字段) |
Returns
void
Remarks
与 replace 的区别在于「脏实体」的处理:replace 会 Object.assign 到 target
并重设 _origin、把 _modified 归零 —— 用户尚未保存的编辑被一并写进基线后 patch 清空,
UI 看起来没变,下一次 save() 却静默 no-op,编辑永久丢失。
这里的语义是:
_origin基线一律前移到外部值(撤销应回到外部推进后的状态,而非更早的陈旧值);- 当前 patch 中仍有真实差异的键保留本地值,不被外部值覆盖;
- 其余键同步为外部值。
patch 随后按「当前值 vs 新基线」重算,因此外部值恰好等于本地编辑时会自然收敛为空
(确实无需再写);_modified 也据此重算,而不是被无条件归零。
removeRelationEntity()
removeRelationEntity(relation, entity): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:563
委托给 EntityRelationCache.remove — 见 relation-cache.ts
Parameters
| Parameter | Type |
|---|---|
relation | EntityRelationMetadata |
entity | any |
Returns
void
replace()
replace(data): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:371
使用外部数据重新同步当前实体引用 用于查询缓存命中后的安全回填,避免通过 Proxy 误记用户修改。
注意:本地 _removed 标志不被清除,避免缓存回填"复活"已标记删除的实体。 用户主动标记删除的状态不应被远端缓存回填覆盖。
Parameters
| Parameter | Type |
|---|---|
data | Partial<InstanceType<T>> |
Returns
void
reset()
reset(): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:348
重置实体状态到初始状态(origin)
操作:
- 删除 proxyTarget 上 origin 没有的 key( :
createEntityRef稀疏水合场景下 构造后才新增的属性在 origin 里从未存在过,仅 Object.assign 无法把它们清除) - 恢复 proxyTarget 的所有属性到 origin 的值
- 清除 modified 标记
- 清空变更历史(patches)
- 递增 generation,作废此前排队但尚未触发的防抖 checkChange(见 #generation 注释)
- 发布空的变更事件
使用场景:撤销所有未保存的修改
Returns
void
setRelationObservableEntry()
setRelationObservableEntry(relation, entry): void;
Defined in: packages/rxdb/src/entity/entity-status.ts:583
委托给 EntityRelationCache.setObservableEntry — 见 relation-cache.ts
Parameters
| Parameter | Type |
|---|---|
relation | EntityRelationMetadata |
entry | RelationObservableEntry |
Returns
void