Hi all,
I have a need to refresh the to-one relationship of an object, so that if someone in another app or perhaps in a different EOF stack within the same app has updated the to-one to point to a different object then I want my EO’s to one to point to the correct EO. I do not want to invalidate the source EO or refetch it because it may have edits in progress.
I searched in Wonder but I was not able to find anything that does this. I came up with the code below last night and it seems to work well so far.
Since this is an advanced EOF topic I thought I should share it to see if anybody wants to code review it, play with it and provide comments on correctness / recommendations / feedback.
This code uses a primaryKeyQualifier() method in my EO which is practically the same as the identityQualifier() concept discussed by Aaron Rosenzweig in an email thread in May of this year.
Thanks in advance for any help.
@SuppressWarnings("rawtypes") public void refreshToOneRelationshipWithKey(String toOneName) { EOEditingContext ec = editingContext(); EOEntity entity = entity(); EORelationship toOne = entity.relationshipNamed(toOneName); String foreignKeyName = toOne.sourceAttributes().lastObject().name(); EOFetchSpecification fs = new EOFetchSpecification(entity.name(), primaryKeyQualifier(), null); fs.setRawRowKeyPaths(new NSArray<String>(foreignKeyName)); @SuppressWarnings("unchecked") NSDictionary<String,Object> dict = (NSDictionary<String,Object>) ec.objectsWithFetchSpecification(fs).lastObject(); Object newForeignKeyValue = dict.allValues().lastObject(); EOGlobalID gid = globalID(); EOModel model = entity.model(); EODatabaseContext dbc = EODatabaseContext.registeredDatabaseContextForModel(model, ec); EODatabase database = dbc.database(); EOObjectStoreCoordinator osc = (EOObjectStoreCoordinator) ec.rootObjectStore(); osc.lock(); try { NSDictionary snapshot = database.snapshotForGlobalID(gid); Object currentForeignKeyValue = snapshot.objectForKey(foreignKeyName); // We don't need to check for null as currentForeignKeyValue and newForeignKeyValue // use NSKeyValueCoding.NullValue to represent null. if (currentForeignKeyValue.equals(newForeignKeyValue) == false) { NSMutableDictionary newSnapshot = snapshot.mutableClone(); newSnapshot.takeValueForKey(newForeignKeyValue, foreignKeyName); database.recordSnapshotForGlobalID(newSnapshot.immutableClone(), gid); Object toOneValue = NSKeyValueCoding.NullValue; if (newForeignKeyValue != NSKeyValueCoding.NullValue) { EOKeyGlobalID toOneGID = ERXEOGlobalIDUtilities.createGlobalID(toOne.destinationEntity().name(), new Object[] {newForeignKeyValue}); toOneValue = ec.faultForGlobalID(toOneGID, ec); } // Update __originalSnapshot() and EO so that changesFromCommittedSnapshot() // does not think that the object has changed. NSDictionary originalSnapshot = __originalSnapshot(); NSMutableDictionary newOriginalSnapshot = originalSnapshot.mutableClone(); newOriginalSnapshot.setObjectForKey(toOneValue, toOneName); __setOriginalSnapshot(newOriginalSnapshot.immutableClone()); if (toOneValue == NSKeyValueCoding.NullValue) { takeStoredValueForKey(null, toOneName); } else { takeStoredValueForKey(toOneValue, toOneName); } } } finally { osc.unlock(); } }
public EOQualifier primaryKeyQualifier() { NSDictionary<String, Object> pkDict = primaryKeyDictionary(false /* inTransaction */); EOEntity entity = entity(); return entity.qualifierForPrimaryKey(pkDict); } |