levitatejay
levitatejay

Reputation: 1278

Deleting and then adding a new identical entity throws an error

I have a model called a DeviceAccount. It is a join table that allows me to create many to many relationships.

I have a function that creates a new DeviceAccount by handing it an account & a device to join. See here:

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

I have a function to delete a DeviceAccount. See here:

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();
    };

If I locally create, remove, create, remove the same device/account pair there is no problem. If I take a device/account pair that exists on the server I can remove it fine, but when I add it again I recieve the following error:

Uncaught Error: This key is already attached: DeviceAccount:#Test.Models-5:::5

If I follow this in more depth I can see that removing a local device changes the entityState to be 'Detached' and if I remove a device that also exists on the server its entityState gets changed to be 'Deleted'. I can't follow much further than this and I was hoping someone could explain why this could be happening?

Upvotes: 3

Views: 1761

Answers (2)

Jay Traband
Jay Traband

Reputation: 17052

Just to be clear, deleting an entity via entityAspect.setDeleted causes its entityState to be set to "Deleted". This action marks the entity for deletion on the next save and also removes it from any navigation collections on the client. The entity is still being tracked by the EntityManager after this operation.

In contrast, detaching an entity via entityAspect.setDetached removes it from the entityManager cache completely. This also removes the entity from any navigation collections on the client, but will have NO effect on the server during an EntityManager.saveChanges call, because the EntityManager no longer "knows" about the entity. Think of "detaching" as telling the EntityManager to completely forget about an entity, as if it had never been queried in the first place.

"Deleting" an entity followed by "re-adding" the same entity is problematic because this would cause the EntityManager to have two incarnations of the same entity; a deleted version and an added version. Therefore the EntityManager throws the exception that you are seeing.

I think what you want to do is delete and add a "new" clone entity with a different id.

Hope this makes sense!

Upvotes: 4

PW Kad
PW Kad

Reputation: 14995

The reason this happens is that Breeze is keeping track of that entity until you have fully removed it from the server to keep you from creating a new entity with the same ID, which of course will throw a server exception since you can't do that.

If you called saveChanges() on your entityManager before you tried to recreate it, then Breeze will go out to the server, remove the entity from the DB, return the promise, and completely detach the entity from the local cache since it no longer exists on the server.

You could set the entityState to detached manually, but then if you try to saveChanges and that ID already exists on the server it will throw an error.

Best Option

Pass the entity into the saveChanges method in an array -

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

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

Now after saveSucceeded has completed you can create a new entity with that ID

Upvotes: 2

Related Questions