peternees
peternees

Reputation: 170

JDO(DataNucleus) collection members are not deleted

I'm using GAE 1.7.0 w/ JDO(DataNucleus). When I persist a class with a collection attribute, removed collection members are not removed from the datastore. I remove the collection members from a detached copy. The new members are correctly added, the existing ones ar not removed, causing my collection to only grow.

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Parent{
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent(defaultFetchGroup="true", dependentElement="true")
    private List<Child> children = new ArrayList<Child>(0);

}

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Child implements Serializable {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String id;

    @Persistent
    @Extension(vendorName="datanucleus", key="gae.parent-pk", value="true")
    private String parentId;
    ....
}

...
parent = pm.detachCopy(resultFromQuery);
// parent looks correct in dubugger: all children are fetched (and detached)
....
parent.getChildren().clear();
parent.getChildren().addAll(newChildren);
for (Child child: parent.getChildren())
    child.setParentId(KeyFactory.createKeyString("Parent", parent.getId()));
// parent looks good in the debugger: old children were removed and new ones added
...
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
    pm.currentTransaction().begin();
    pm.makePersistent(parent);
    pm.currentTransaction().commit();
} catch (Exception e) {
} finally {
    if (pm.currentTransaction().isActive())
        pm.currentTransaction().rollback();
    if (!pm.isClosed())
        pm.close();
}
// problem in datastore: new children were created, old ones not removed

I noticed that if I do the query-remove-persist in a transaction (without detaching the object), then the problem is solved. This is an ok temporal work-around, but I would still want to do the update on the detached object.

Upvotes: 2

Views: 493

Answers (1)

Ian Marshall
Ian Marshall

Reputation: 760

I am not an expert on JDO, but here goes....

Each Parent and its related Child entities are in the same entity group. Therefore, you will need to do your datastore updates within a transaction, since a given entity group may not be updated with a frequency of more than around once per second. Also, within a transaction the enhancement magic will work: hidden, added Java bytecode which will handle things like adding and removing children, and setting field values.

If you do not want to do this, then one way is not to store a list of Child entities in the Parent; store a list of Child IDs and/or primary keys instead. This will result in each Child being in its own entity group. But even then, you will be able to update each Parent (list) only once per second.

Upvotes: 1

Related Questions