删除然后添加新的相同实体会引发错误

时间:2013-10-15 11:08:30

标签: breeze

我有一个名为DeviceAccount的模型。它是一个连接表,允许我创建多对多的关系。

我有一个功能,通过将帐户和帐户交给我来创建一个新的DeviceAccount。要加入的设备。见这里:

var createDeviceAccount = function (account, device) {
        var initialValues = {
            account: account,
            device: device
        };
        return manager.createEntity(entityNames.deviceAccount, initialValues);
    };

我有删除DeviceAccount的功能。见这里:

var deleteDeviceAccount = function (account, device) {
        var baseQuery = entityQuery.from('DeviceAccounts');
        var p1 = new breeze.Predicate('device', 'eq', device);
        var p2 = new breeze.Predicate("account", "eq", account);
        var modQuery = baseQuery.where(p1.and(p2));
        var results = manager.executeQueryLocally(modQuery);
        results[0].entityAspect.setDeleted();
    };

如果我在本地创建,删除,创建,删除相同的设备/帐户对,则没有问题。 如果我使用服务器上存在的设备/帐户对,我可以将其删除,但是当我再次添加它时,我收到以下错误:

  

未捕获错误:此密钥已附加:   DeviceAccount:#Test.Models-5 ::: 5

如果我更深入地了解这一点,我可以看到删除本地设备会将entityState更改为“Detached”,如果我删除了服务器上也存在的设备,则其entityState将更改为“Deleted”。我不能比这更进一步,我希望有人可以解释为什么会发生这种情况?

2 个答案:

答案 0 :(得分:4)

为了清楚起见,通过entityAspect.setDeleted删除实体会导致其entityState设置为“Deleted”。此操作在下次保存时标记要删除的实体,并将其从客户端上的任何导航集合中删除。在此操作之后,EntityManager仍在跟踪实体。

相反,通过entityAspect.setDetached分离实体将其从entityManager缓存中完全删除。这也会从客户端上的任何导航集合中删除实体,但在EntityManager.saveChanges调用期间对服务器没有影响,因为EntityManager不再“知道”该实体。将“分离”想象为告诉EntityManager完全忘记一个实体,就好像它从来没有被查询过一样。

“删除”一个实体,然后“重新添加”同一个实体是有问题的,因为这会导致EntityManager有两个相同实体的化身;删除的版本和添加的版本。因此,EntityManager会抛出您看到的异常。

我认为您要做的是删除并添加具有不同ID的“新”克隆实体。

希望这是有道理的!

答案 1 :(得分:2)

发生这种情况的原因是Breeze跟踪该实体,直到您完全从服务器中删除它,以防止您创建具有相同ID的新实体,这当然会引发服务器异常,因为您可以'那样做。

如果在尝试重新创建它之前在entityManager上调用了saveChanges(),那么Breeze将转到服务器,从数据库中删除实体,返回承诺,并将实体与本地缓存完全分离,因为它服务器上不再存在。

您可以手动将entityState设置为分离,但是如果您尝试saveChanges并且该ID已经存在于服务器上,则会抛出错误。

最佳选择

将实体传递给数组中的saveChanges方法 -

results[0].entityAspect.setDeleted();
manager.saveChanges([results[0]]).then(saveSucceeded);

function saveSucceeded() {
    console.log('Entity removed from server');
}

现在,在saveSucceeded完成后,您可以创建一个具有该ID的新实体