RestKit POSTed managed object becomes duplicate when response is enveloped in an array - ios

When I POST a Core Data managed object using RestKit, RestKit doesn't update the existing object but creates a new object instead.
The returned JSON always contains the newly created object, but wraps it into a plural keyed array. I found that if I change this to just the one object, the updating works as expected. However, I would like to keep the array in the response so that all responses are consistently in the plural form.
Is there any way I can make RestKit update the record, even when returned from the server wrapped in an array?
Possible solution: identificationAttribute?
On my entities I have an identificationAttribute called remoteID. This is the primary unique key of the record. This will be 0 before the POST, because the object is not yet on the server. I thought that by adding a second identificationAttribute called insertionID, setting that before the POST, and then returning it in the response, would allow RK to find the existing entity in the local store. Alas, it didn't work.
What did work however, was setting the remoteID before the POST, to the next auto increment value on the server! What could explain that it works with remoteID, but not with a second insertionID?
Example request
{
"user": {
"email": "example#example.com"
}
}
Response
{
"users": [{
"email": "example#example.com"
}]
}

I would like to keep the array in the response so that all responses are consistently in the plural form.
You shouldn't, because this is an individual request and response, not a composite.
Your idea about identificationAttribute is correct, but doesn't apply when the response is an array. The array is the trigger (or one of the possible triggers) to abandon the match with the source object and create new objects. Changing this would be hard.
Without knowing more about your real situation, 2 alternatives:
Change the JSON
POST a dictionary instead of the real object and then you won't have a duplicate
When you use multiple identification attributes, all must match for the destination object to be found.
Take care - don't create multiple mappings for the same entity with different identification attributes or you will most likely be debugging the lookup cache for a long time trying to work out what's happening...
If the identity matches before the request is made then the array isn't an issue. To explain the above in more detail:
When you POST an object, RestKit expects to get that object back. So, if you POST one object and get an array back it doesn't know what to do, because it can't map an array into an object. So, it tries to lookup based on the identification attribute (if they exist). If the POSTed object didn't have an id and the returned object does then it will never match. If you set it before POSTing then it will match.

Related

Can I specify a objectId when creating new PFObjects?

Swift / iOS
Can anyone tell me if it is possible to specify the PFObject objectId value when creating new objects?
I've obviously attempted but the save fails. (which might just be the answer)
The reason I am asking is I wondered if anyone had found a "trick" that would allow me to specify.
I am using PFObject.saveInBackground { method to persist the new object.
No you can not. Parse sets the objectId on the server during the save operation.
The reason your operation is failing is because Parse is looking for an object on the server with the id that you are specifying and is then trying to update that object but it cannot find the object.

RESTKit: Overwriting objects where the objectID is the same, but other attributes have changed.

When I GET the server, I check the attribute "objectID" on each object, and if the objectID is already in the local store, I don't store the object.
Question: What's the approach if the "objectID" exists, but its other attributes have changed and thus the entire object should be replaced with the new object? There is an other attribute called "lastModified" that will change. Do I compare against both "objectID" and "lastModified"?
Generally, yes, compare the id and then check the modified date. Try not to replace the object though, instead, pass the new object to the existing object and have it update itself (then throw away the new object).
Note that if you were using Core Data then RestKit could handle this for you using unique identifier (so it can find the existing objects and update them during the mapping process).

Restkit - Core Data One-To-One Relationship Mapping via Foreign Key

I have spent the last few hours trying a number of different solutions to this problem by looking at similar similar problems that have been resolved on StackOverFlow threads.
However, I have hit a brick wall.
Some background.
Using Restkit 0.22 and Core Data to Persist 2 Objects and set up a relationship between them.
The two Objects that I am modelling are as follows, Relationships are also included in the form of a One-One relationship between COAgendaItem and COMapItemLocation (The relationship that isn't working at present) and a One-Many between COMapItemLocation and COAgendaItem (I have not looked at mapping this yet):
-- COAgendaItem
-- COMapItemLocation
They have the Corresponding Attributes and Relationships
The desired result is to have the core data relationship working alongside RestKit, i.e. The property agendaItemLocation accessible via code on a COAgendaItem object.
The JSON Response from the Server looks like this
The above JSON Response is the data required for a COAgendaItem object plus the primary key of a COMapItemLocation Object. I am having a problem mapping the location_id field which is the primary key of a COMapItemLocation. (I have the Response Descriptors and the retrieval code set up and it is working correctly, it has only become a problem since I attempted to map a relationship)
So far I have modified my RKEntityMapping to try and map the relationship.
+ (RKMapping *)agendaItemMapping{
RKEntityMapping *agendaItemMapping = [RKEntityMapping mappingForEntityForName:#"COAgendaItem" inManagedObjectStore:[[COPersistenceCoordinator sharedCOPersistenceCoordinator]restKitObjectStore]];
[agendaItemMapping addAttributeMappingsFromDictionary:#{#"id": #"agendaItemID",#"title": #"agendaItemTitle",#"description": #"agendaItemDescription",#"start": #"agendaItemStartTime",#"end": #"agendaItemEndTime",#"category": #"agendaItemCategory",#"location_id" : #"agendaItemLocation"}];
[agendaItemMapping addConnectionForRelationship:#"agendaItemLocation" connectedBy:#"location_id"];
return agendaItemMapping;
}
However this causes a crash on launch as shown below (Note, I have added the #"location_id" : #"agendaItemLocation" mapping for the foreign key in the default mapping as well, is this necessary)
I have tried modifying the [agendaItemMapping addConnectionForRelationship:#"agendaItemLocation" connectedBy:#"location_id"];
Statement with all the combinations I can think of both in single string and dictionary formats i.e. #{"agendaItemLocation" : #"location_id"} but whatever I try, it always ends up in the same error as before 'Cannot connect relationship: invalid attributes given for source entity 'COAgendaItem': location_id'.
I am completely stumped on this one, can anyone point anything that I have done wrong or need to do differently?
Thanks greatly for any help in advance! :)
You describe 2 different relationships, but really you just have one with an inverse. This is correct, it's just your description which is wrong (and thus probably your understanding of setting the relationship contents).
The connection cannot be made (and you get an error) because RestKit needs to know the id of the other object to find (to connect to). You're telling it to use location_id, but it needs to be a property on the class (usually transient), not an item in the JSON (because the connection is made after the JSON has been processed and gone).
Add a property to the entity and a mapping to place the location_id into it. Update the connection with the name of that property.

RestKit 0.20 and ManagedObjectContexts

I am mapping data using RestKit 0.20 into a Core Data and displaying it in a UITable. I am writing the data, an 'Activity' object, to the mainQueue's ManagedObjectContext and it all works fine. Now I need a second table with Future-Activities and also a third table with Past-Activities. I need a ManagedObjectContext for each table as the sorting is done on the server side. How can I handle this and have persistent data. Is 'newChildManagedObjectContextWithConcurrencyType' what I need to use?
Keep a single store. Use a predicate to filter out the items you want.
If you can download all of the data (and you're happy to do that even though some of it may not be used by the user), and you can tag them for what they are used for then that is an option.
From a RestKit point of view, you can use metadata to tag the items during the mapping process so that you know how they should be used (and then filter on that). This requires that you add a new key to the item - but, if one item could be in all responses this will be problematic because the values would get overwritten.
To use metadata, simply add a new mapping like:
#"#metadata.URL": #"requestURL"
Where #metadata.URL is the URL used to make the request and requestURL is the property on your entity that you can use for filtering. The predicate will check for contains your types ("all_day" "start_time" "end_time").

Core Data Object for ID Only Found Once

I've got a huge xml File which needs to be parsed.
For different Tags inside the xml, e.g Football Soccer Data, I create NSManagedObjects e.g. SoccerPlayer and so forth.
I also need to use these objects a few times within the parsing method and so I created an Object which finds me the right object for the id I provide.
This works fine for the first game inside the xml but won't work for any one after that.
Could be the problem that I have to delete a few objects as I parse through the xml?
For my XML Parsing Framework, I use TouchXML.
Has anyone else experienced this behaviour before?
I agree with the comment that some code would help -- it's hard to understand exactly what the problem is. Nevertheless, I'll point out that the documentation for NSManagedObject's -objectID says:
Important: If the receiver has not yet been saved, the object ID is a
temporary value that will change when
the object is saved.
So, if you're creating an object, storing it's objectID, saving the context, and then trying to find the object with the objectID that you stored, you're probably going to fail because the temporary objectID was replaced with a permanent one when the context was saved.

Resources