跳到主要内容

EntityStatus<T>

Defined in: packages/rxdb/src/entity/entity-status.ts:37

实体状态管理器

职责:

  1. 状态跟踪:local/remote/modified/removed 标记实体的生命周期状态
  2. 变更记录:记录实体的所有变更历史(patches),支持撤销/重做
  3. 关系管理:维护实体间的关系缓存,处理级联操作
  4. 变更通知:通过 RxJS Subject 发布实体变更事件

架构设计:

  • 使用 Proxy 拦截属性修改,自动记录变更
  • 关系缓存由 EntityRelationCache 子模块管理(含多对多 Junction 延迟删除)
  • 懒加载缓存(patch/fingerprint),按需计算避免性能浪费

Type Parameters​

Type ParameterDescription
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​
ParameterType
valueboolean
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​
ParameterType
valueboolean
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​
ParameterType
valueInstanceType<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​
ParameterType
valueboolean
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​
ParameterType
valueboolean
Returns​

void

Methods​

addRelationEntity()​

addRelationEntity(relation, entity): void;

Defined in: packages/rxdb/src/entity/entity-status.ts:558

委托给 EntityRelationCache.add — 见 relation-cache.ts

Parameters​

ParameterType
relationEntityRelationMetadata
entityany

Returns​

void


applyExternal()​

applyExternal(data): void;

Defined in: packages/rxdb/src/entity/entity-status.ts:450

应用一份外部数据,并按实体当前是否有未保存编辑自动选择合并策略。

Parameters​

ParameterTypeDescription
dataPartial<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

记录实体变更

机制:

  1. 计算当前 patch 和 inversePatch
  2. 将变更记录追加到 patches 数组
  3. 通过 Subject 发布变更事件

时间戳说明:

  • recordAt: 业务时间(Date),用于显示和排序
  • timeStamp: 性能时间(performance.now),用于高精度计时和排序

Parameters​

ParameterTypeDescription
recordAtDate变更记录时间,默认当前时间

Returns​

void


cleanRelationEntity()​

cleanRelationEntity(relation): void;

Defined in: packages/rxdb/src/entity/entity-status.ts:568

委托给 EntityRelationCache.clean — 见 relation-cache.ts

Parameters​

ParameterType
relationEntityRelationMetadata

Returns​

void


getNeedRemoveEntities()​

getNeedRemoveEntities(): object[];

Defined in: packages/rxdb/src/entity/entity-status.ts:533

获取需要删除的实体列表

删除策略:

  • 多对多关系:删除 Junction 实体(中间表记录)
  • 其他关系:不自动删除关联实体(由业务层决定)

Junction 实体处理:

  1. removeRelationEntity 时加入 #remove_junction_set
  2. 保存时统一删除(保证事务一致性)
  3. 只删除 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

获取需要保存的实体列表

逻辑:

  1. 始终包含当前实体(this.proxyTarget)
  2. 遍历所有关系类型的缓存
  3. 筛选出 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​

ParameterType
relationEntityRelationMetadata

Returns​

Set<any>


getRelationObservableEntry()​

getRelationObservableEntry(relation): RelationObservableEntry | undefined;

Defined in: packages/rxdb/src/entity/entity-status.ts:578

委托给 EntityRelationCache.getObservableEntry — 见 relation-cache.ts

Parameters​

ParameterType
relationEntityRelationMetadata

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​

ParameterTypeDescription
keykeyof 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​

ParameterTypeDescription
dataPartial<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​

ParameterType
relationEntityRelationMetadata
entityany

Returns​

void


replace()​

replace(data): void;

Defined in: packages/rxdb/src/entity/entity-status.ts:371

使用外部数据重新同步当前实体引用 用于查询缓存命中后的安全回填,避免通过 Proxy 误记用户修改。

注意:本地 _removed 标志不被清除,避免缓存回填"复活"已标记删除的实体。 用户主动标记删除的状态不应被远端缓存回填覆盖。

Parameters​

ParameterType
dataPartial<InstanceType<T>>

Returns​

void


reset()​

reset(): void;

Defined in: packages/rxdb/src/entity/entity-status.ts:348

重置实体状态到初始状态(origin)

操作:

  1. 删除 proxyTarget 上 origin 没有的 key( :createEntityRef 稀疏水合场景下 构造后才新增的属性在 origin 里从未存在过,仅 Object.assign 无法把它们清除)
  2. 恢复 proxyTarget 的所有属性到 origin 的值
  3. 清除 modified 标记
  4. 清空变更历史(patches)
  5. 递增 generation,作废此前排队但尚未触发的防抖 checkChange(见 #generation 注释)
  6. 发布空的变更事件

使用场景:撤销所有未保存的修改

Returns​

void


setRelationObservableEntry()​

setRelationObservableEntry(relation, entry): void;

Defined in: packages/rxdb/src/entity/entity-status.ts:583

委托给 EntityRelationCache.setObservableEntry — 见 relation-cache.ts

Parameters​

ParameterType
relationEntityRelationMetadata
entryRelationObservableEntry

Returns​

void