The problem is, that the ArrayList's delegate and backingstore are not
consistent. Delegate contains the list sorted as per list-ordering clause,
whereas backingstore fetches the list from the datastore which is not sorted.
So on delete, the backingstore gets the index of the item to be deleted from
delegate list, and datastore has incorrect entry for that index.
User class
public class User {
@Persistent
private String firstName;
@Persistent
private String lastName;
@PrimaryKey
private Key key;
@Persistent
private String email;
@Persistent(defaultFetchGroup="true")
@Element(dependent = "true")
@Order(extensions = @Extension(vendorName="datanucleus",key="list-ordering", value="userEmail asc, name asc"))
private List<Item> items;
//getters and setters
}
Item Class
@PersistenceCapable
public class Item implements DataModel{
@Persistent
private String userEmail;
@Persistent
private String name;
@PrimaryKey
@Persistent
private Key key;
//getters and setters
}
Now add the following two items
{"userEmail":"test2@gmail.com","name":"zzz"}
{"userEmail":"test2@gmail.com","name":"hhh"}
Note list ordering for name field is asc. The datastore has following entry.
agpjb3N0cGVydXNlchgLEgRVc2VyIg50ZXN0QGdtYWlsLmNvbQw 14 test@gmail.com
test@gmail.com [User("test@gmail.com")/Item("zzz"),
User("test@gmail.com")/Item("hhh")]
The list is ordered correctly when the data is retrieved, so when I query the
user, I get item "hhh" followed by "zzz" which is fine.
{"items":[{"type":"item","userEmail":"test@gmail.com","name":"hhh"},
{"type":"item","userEmail":"test@gmail.com","name":"zzz"}]}
The problem is with delete, when I delete "hhh", it ends up deleting entry
"zzz" from the datastore.
try{
tx.begin();
user.getItems();
user.removeItem(item);
pm.makePersistent(user);
tx.commit();
} catch (Exception e) {
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
} finally {
if (tx.isActive()) {
tx.rollback();
}
pm.close();
}
Here is the removeItem code
public synchronized void removeItem(Item item) {
for (Iterator<Item> iter = items.iterator(); iter.hasNext();) {
Item storedItem = iter.next();
if (storedItem.getKey().equals(item.getKey())) {
iter.remove();
}
}
this is what is happening
When the user class is loaded, FetchFieldManager.java orders the item list as
per the ordering clause.
so the User object has sco.backed.ArrayList whose delegate has the item list is
sorted by name.
When iter.remove is called above, it calls ArrayList.remove and this calls the
backingStore (FKListStore) remove with the index of the item to be deleted.
This index does not match the datastore index because the list is not sorted in
the datastore and hence it ends up deletng the wrong entry.
Original issue reported on code.google.com by mona.ah...@gmail.com on 21 Feb 2013 at 10:33
Original issue reported on code.google.com by
mona.ah...@gmail.com
on 21 Feb 2013 at 10:33