Thanks Aaron, your suggestion is working well.  It is analogous to a "git 
rebase” ;-)  I feel better with this code.

I did find that the technique did not work for to-many relationships, but added 
a bit of code towards the end of the method to refresh the to-many 
relationships using Wonder:

    /**
     * Core method to refresh properties selectively with data from the 
database. The
     * properties can be attributes, to-one or to-many relationships.
     */
    public void refreshProperties(NSArray<String> keys) {
        NSDictionary<String, Object> changes = changesFromCommittedSnapshot();

        // Discard changes to the properties that we're about to refresh if any
        NSMutableDictionary<String, Object> changesToKeepAfterRefresh = 
changes.mutableClone();
        changesToKeepAfterRefresh.removeObjectsForKeys(keys);

        // Now fetch the receiver refreshing it with changes from database
        EOEntity entity = entity();
        EOFetchSpecification fs = new EOFetchSpecification(entity.name(), 
primaryKeyQualifier(), null);
        fs.setRefreshesRefetchedObjects(true);
        editingContext().objectsWithFetchSpecification(fs);

        // Now re-apply the changes we want to keep
        if (changesToKeepAfterRefresh.count() > 0) {
            takeValuesFromDictionary(changesToKeepAfterRefresh);
        }

        // The above will not refresh to-many relationships so do something a 
bit
        // more drastic to refresh the to-many relationships.
        for (String key : keys) {
            EORelationship relationship = entity.relationshipNamed(key);
            if (relationship.isToMany()) {
                ERXEOControlUtilities.clearSnapshotForRelationshipNamed(this, 
key);
            }
        }
    }

And some convenient methods to go with it too:

    /**
     * Convenience method to refresh properties selectively with data from the 
database.
     * The properties can be attributes, to-one or to-many relationships.
     */
    public void refreshProperties(String... keys) {
        NSArray<String> keysArray = new NSArray<String>(keys);
        refreshProperties(keysArray);
    }

    /**
     * Convenience method to refresh properties selectively with data from the 
database.
     * The properties can be attributes, to-one or to-many relationships.
     */
    public void refreshProperties(ERXKey<?>... erxKeys) {
        NSMutableArray<String> keys = new 
NSMutableArray<String>(erxKeys.length);
        for (ERXKey<?> erxKey : erxKeys) {
            keys.add(erxKey.key());
        }
        refreshProperties(keys);
    }



> On Sep 3, 2016, at 4:45 PM, Aaron Rosenzweig <[email protected]> 
> wrote:
> 
> Hi Ricardo,
> 
> That’s some clever WO-ninja magic you got going on there. I’ve never replaced 
> the original snapshot of an EO before.
> 
> If it works, great - I won’t knock it but I’d be scared without flexing it 
> (using it a bunch). 
> 
> Another idea… 
> 
> 1) hold onto the “changesFromCommittedSnapshot” so you can refer to it.
> 
> 2) in your fetchSpec make “setRefereshesRefetchedObjects()” to true - so when 
> you go round trip you’ll update the EO.
> 
> 3) reapply your changes from the committed snapshot.
> 
> Cheers,
> AARON ROSENZWEIG / Chat 'n Bike <http://www.chatnbike.com/>
> e:  [email protected] <mailto:[email protected]>  t:  (301) 956-2319      
>         
>       
> 
>> On Sep 3, 2016, at 9:34 AM, Ricardo Parada <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> 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);
>>     }
>> _______________________________________________
>> Do not post admin requests to the list. They will be ignored.
>> Webobjects-dev mailing list      ([email protected] 
>> <mailto:[email protected]>)
>> Help/Unsubscribe/Update your Subscription:
>> https://lists.apple.com/mailman/options/webobjects-dev/aaron%40chatnbike.com 
>> <https://lists.apple.com/mailman/options/webobjects-dev/aaron%40chatnbike.com>
>> 
>> This email sent to [email protected]
> 

 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to