Breeze.js - 删除新的 (EntityState = "Added") 实体时未清除外键
Breeze.js - foreign keys not cleared when deleting a new (EntityState = "Added") entity
我注意到在 Breeze.js 中删除一个尚未持久化的实体 (EntityState = "Added") 和一个持久化的实体关于它的任何引用(外键)之间存在令人讨厌的差异。
这可能是与为新实体生成临时密钥有关的问题。在这种情况下,我们为临时键 (id) 生成负数,并在持久化时替换为实际键。
这将通过具体示例更容易地解释。假设我们有一个名为 Person 的实体,它包含对 Title 实体("Mr"、"Mrs" 等)的引用:
export class Person extends EntityBase {
id: number;
firstName: string;
lastName: string;
titleId: number;
title: Title;
...
}
export class Title extends EntityBase {
id: number;
name: string;
...
}
现在,如果我们在当前上下文中有一个持久化的 Title 实体并在其上调用 .setDeleted(),则会设置适用的 Person 实体上的 titleId 属性 和标题导航 属性为空。
但是,如果 Title 实体的 EntityState 为 "Added",则只有所有链接的 Person 实体上的标题导航 属性 设置为 null。 titleId 属性 保留其值,导致保存时出错(违反外键约束)。
这意味着删除 EntityState 为 "Added" 的 Title 实体需要将所有链接的 Person 实体的 titleId 属性 显式设置为 null。
可能值得注意的是,基础数据库中的 TitleID 列可以为空。如果不是,我们当然必须将 titleId 属性 设置为合适的值。
不得不这样做似乎很笨拙。这种行为是故意的,出于某种让我逃避的原因吗?
关于删除,Breeze 对
进行了重要区分
- (案例 a) 实体仅存在于客户端(那些处于已添加状态),并且
- (case b) 已持久保存在服务器上的实体。
对于已经持久化的实体 (案例 b),Breeze 必须跟踪已删除的实体,
并将删除发送到服务器。必须更新服务器上的任何外键
删除对已删除实体的引用,因此breeze会相应地更新相关的客户端实体
并将这些更改也发送到服务器。
对于新创建的实体(案例a),服务器对此一无所知。几时
"deleted" 在客户端上,Breeze 实际上并没有设置它 Deleted
,因为它没有
需要向服务器发送删除。相反,它设置 Detached
.
设置实体时 Detached
,其导航属性设置为 null,并且它
从 EntityManager 的缓存中删除。它的外键属性没有改变,
但是,如果您分离一个实体并重新附加它,导航属性将
被重新连接。无论实体是 Added
还是之前的任何其他状态,都是如此
它变成了 Detached
.
有关实体状态的更多信息,请参阅 Breeze documentation
我认为这实际上是应该修改 Breeze 以更智能地处理 Added
实体删除的情况。不过与此同时,以下可能是一种解决方法(到目前为止我还没有机会尝试)。
首先,对于 Added
个被删除的实体,问题似乎是引用该实体的导航属性没有得到更新以删除这些引用。或许可以诱骗 Breeze 来照看它。
- 首先将要删除的已添加实体的状态设置为
Unchanged
。
- 删除实体。因为实体的状态不再是
Added
,将 Delete 转换为 Detach 的逻辑将不适用。该实体的状态将设置为 Deleted
,并且引用它的导航属性将被更新,因此它们不再如此。
- 让实体处于
Deleted
状态将是一个问题,因为会尝试删除实际上并不存在的实体。将其状态设置为分离以防止这种情况。
因此,与其直接删除,不如尝试将状态设置为 Unchanged
,然后删除,最后将状态设置为 Detached
。
我注意到在 Breeze.js 中删除一个尚未持久化的实体 (EntityState = "Added") 和一个持久化的实体关于它的任何引用(外键)之间存在令人讨厌的差异。
这可能是与为新实体生成临时密钥有关的问题。在这种情况下,我们为临时键 (id) 生成负数,并在持久化时替换为实际键。
这将通过具体示例更容易地解释。假设我们有一个名为 Person 的实体,它包含对 Title 实体("Mr"、"Mrs" 等)的引用:
export class Person extends EntityBase {
id: number;
firstName: string;
lastName: string;
titleId: number;
title: Title;
...
}
export class Title extends EntityBase {
id: number;
name: string;
...
}
现在,如果我们在当前上下文中有一个持久化的 Title 实体并在其上调用 .setDeleted(),则会设置适用的 Person 实体上的 titleId 属性 和标题导航 属性为空。
但是,如果 Title 实体的 EntityState 为 "Added",则只有所有链接的 Person 实体上的标题导航 属性 设置为 null。 titleId 属性 保留其值,导致保存时出错(违反外键约束)。
这意味着删除 EntityState 为 "Added" 的 Title 实体需要将所有链接的 Person 实体的 titleId 属性 显式设置为 null。
可能值得注意的是,基础数据库中的 TitleID 列可以为空。如果不是,我们当然必须将 titleId 属性 设置为合适的值。
不得不这样做似乎很笨拙。这种行为是故意的,出于某种让我逃避的原因吗?
关于删除,Breeze 对
进行了重要区分- (案例 a) 实体仅存在于客户端(那些处于已添加状态),并且
- (case b) 已持久保存在服务器上的实体。
对于已经持久化的实体 (案例 b),Breeze 必须跟踪已删除的实体, 并将删除发送到服务器。必须更新服务器上的任何外键 删除对已删除实体的引用,因此breeze会相应地更新相关的客户端实体 并将这些更改也发送到服务器。
对于新创建的实体(案例a),服务器对此一无所知。几时
"deleted" 在客户端上,Breeze 实际上并没有设置它 Deleted
,因为它没有
需要向服务器发送删除。相反,它设置 Detached
.
设置实体时 Detached
,其导航属性设置为 null,并且它
从 EntityManager 的缓存中删除。它的外键属性没有改变,
但是,如果您分离一个实体并重新附加它,导航属性将
被重新连接。无论实体是 Added
还是之前的任何其他状态,都是如此
它变成了 Detached
.
有关实体状态的更多信息,请参阅 Breeze documentation
我认为这实际上是应该修改 Breeze 以更智能地处理 Added
实体删除的情况。不过与此同时,以下可能是一种解决方法(到目前为止我还没有机会尝试)。
首先,对于 Added
个被删除的实体,问题似乎是引用该实体的导航属性没有得到更新以删除这些引用。或许可以诱骗 Breeze 来照看它。
- 首先将要删除的已添加实体的状态设置为
Unchanged
。 - 删除实体。因为实体的状态不再是
Added
,将 Delete 转换为 Detach 的逻辑将不适用。该实体的状态将设置为Deleted
,并且引用它的导航属性将被更新,因此它们不再如此。 - 让实体处于
Deleted
状态将是一个问题,因为会尝试删除实际上并不存在的实体。将其状态设置为分离以防止这种情况。
因此,与其直接删除,不如尝试将状态设置为 Unchanged
,然后删除,最后将状态设置为 Detached
。