I am using coredata to save the server data through web services in my application and I am storing relationships as an object to the entity.
I have many entities e.g "Inspirations" and "Products" and both are related to each other. I have a problem whenever the records are updated in the third entity which is "Filters" then the relations of the entities broke and I cannot apply filters on the entities.
[object addRelatedInspirationsObject:related];
This is how I save relationships. I am not able to figure out why the relations are being broken once the entity is updated which has no direct link with the entity.
One thing more if I fetch and save the data of any one of the entities like "Inspirations" then all the relations start to work again.
Your code should work. Here are 2 things you need to check:
Make sure related is not nil when you call your method.
Make sure you call save on a valid managed object context.
From your question it seems that entities have 1 to many relationship between them. And by the code you supplied, every things should work fine. Just make sure, you are using the Filter object from the relationship like object.filter (or obj1.obj2.filter), not accessing it via a direct NSPredicate on Filter entity and updating it. And if you are using FRC, you might also need to generate a fault against the parent entities, to get your UI updates.
Related
I am working on an events app that syncs "Events" with a JSON API using Restkit. The mapping looks roughly like this.
var eventsMapping = RKEntityMapping(forEntityForName: "Event", inManagedObjectStore: managedObjectStore)
eventsMapping.identificationAttributes = ["eventID", "name", "eventDescription"]
eventsMapping.addAttributeMappingsFromDictionary([
"id":"eventID",
"title":"name",
"description":"eventDescription",
(more mapping attributes here, etc...)
])
The events are displayed using a NSFetchedResultsController. Locally, there is a 'User' NSManagedObject that is created...however this object is just local to the app and is not synced to the server via Restkit. The "User" has a one-to-many relationship with Events, with the purpose that a user can "save" events that they are attending. (Note: Right now, both sides of the Core Data relationship delete rules is set to "no action.") The save is roughly done this way.
var managedObjectContext = RKManagedObjectStore.defaultStore().mainQueueManagedObjectContext
currentUser.mutableSetValueForKey("events").addObject(event)
managedObjectContext?.saveToPersistentStore(&error)
So far everything works great, selected events are stored and saved successfully with the user and persists through app relaunches as expected. However, there is one scenario that causes an event to be removed from the user and that is when an update is made to that particular event on the server. When Restkit detects this and updates the event, according to breakpoints I placed in the NSFetchedResultsController didChangeObject, apparently Restkit and/or Core Data is actually deleting the event and then inserting it back with the updates. This is transparent and just fine in most cases, but in this case I'm thinking the initial delete is what is breaking off the event from the user.
Of course, the eventsMapping above doesn't reference any relationship to a user in any way, so that could be another reason why the relationship is broken off. I have been reading more about Restkit relationships and I have used relationship / property mappings in Restkit before successfully to relate objects, but in that scenario both objects existed on the API. In this case, the User here isn't a part of the API at all, only local as I explained. So should I still be using a Restkit relationship mapping? Or perhaps I should be trying to accomplish all of the above via another way?
I figured out the answer, I made a goof in the code above. On the identification attributes for the mapping, I had three different properties in there, when I only should have used the one with the primary key that would never change (eventID).
eventsMapping.identificationAttributes = ["eventID"]
What apparently was happening was because I specified the title/name as an identification attribute, whenever that title changed on the server Restkit would identify it as a new/different object and delete the "old" object and insert the "new" one. When I changed it only to specify the primary key, it triggered an update instead and my relationship with the user persisted.
One more note for others that threw me at first: some older info I came across that helped me solve this said to use a primaryKeyAttribute on the mapping. This is apparently dated information: use the identificationAttributes instead.
I'm in the process of removing RestKit from our iOS app. I'm able to get things that I want into Core Data, but they're not really connected.
For example, we have one network call that returns a list of "Category"s (which have a "categoryID" and a "categoryName"; "Category"s also map to-many "StoreLocation"s). We then have another network call that returns a list of "StoreLocation"s (which, among other things, have a "storeName", "storeID", "storeCategoryIDs"; "StoreLocation"s also map to-many "Category"s).
With RestKit, I could use a RKConnectionDescription to describe that "storeCategoryIDs" drove the relationship to-many "Category"s. With that, if I had a given Category object, I could easily determine which StoreLocations belonged to that category.
I'm struggling to see how to accomplishing this without any RestKit dependencies. I suppose I could, whenever I'm about to insert a new Category or new StoreLocation, fetch all of the opposite managed objects and do this manually, but I seem to be missing some component of Core Data that can do.
The main part you're missing is the predicate applied to the fetch and which uses the identification attributes to find the appropriate existing objects. You do need to run your own fetch as core data will not magically update one object if you create a different new object and insert it.
I found a question very similar to mine here, but it was un-replied to and unanswered so I will try again.
I may be missing something in regards to cascade deletes and core data. I am used to cascade deletes working as designed in RDBMS apps but having issues with core data.
I have an object record that get's inserted into entity via an "add form" called modally from a table view. No problem.
In another session I will insert objects into a related details entity (many) where there is a common loadID attribute in both. No problem.
In another session, I will call up the original table view to view the parent "loads", and swipe-delete, save the context, and the parent load gets deleted from the one side entity. No problem, (except apparently details objects in a many side entity do not get removed)
When I open the sqlite data source with a db manager, I see the child records (pay detail items) are being orphaned. I have double and triple checked the cascade delete settings in the relationships. Have tried different entity relationship settings combinations, but nothing seems to get the many records to automatically delete along with the parent record.
If you can't define corresponding keys in core data, how does core data know what belongs to what when you operate in multiple sessions (contexts) adding child objects to the many-side entity?
I don't know if I'm doing something wrong or missing a vital step prior to inserting new child objects in the many table, or doing something wrong or missing a step when deleting the parent object.
But I would suggest all with cascade deletes set to open your data file and be sure there are not orphaned objects (records)
When I retrieve an entity from the one side of a one-to many relationship, I create a mutable array from the set that is the collection of entities from the relationship. I manipulate, edit or otherwise change those entities, possibly delete existing or add new.
When through with the changes I simply use the array to create a new set then replace the original set with that which I created like so:
self.myOneSideEntity.theManySideEntitiesRelationship = [NSSet setWithArray:myNewArrayOfEntities];
It occurred to me that replacing the set may not be deleting the old members. What happened to them? Is this the proper way to edit the collection of related objects? Am I leaving any kind of orphans or going against best practices with this technique?
My relationship is set up with an inverse, cascade delete on the one side, nullify on the many side and the inverse relationship is not optional.
I've spent some days to understand similar behavior in my application.
Relation's "Delete Rule" works only when the object that contains relation is deleted itself. If you simply replace one set of objects with another (as you do) - nothing happens. Child objects that were in old set will simply have inverse relations set to nil. So if that relation (from child side) is not optional, you will get CoreData error when saving context.
For now I didn't find any way to manage this, except manual deletion of old objects.
For me the issue was with getting objects which were wired with current object. (groupObject.docs)
It was solved when I add context by which I get this data.
I'm using MagicalRecord:
[GroupObject MR_findAllInContext:[NSManagedObjectContext MR_defaultContext]]
instead of
[GroupObject MR_findAll]
I'm implementing core data in my iphone app. It has two entities.
Entity1: LatestData
Entity2: LatestDetailedData
LatestData has URL, publishedDate, heading
LatestDetailedData has URL, NewsDescription, PublishedDate, Author
Both entities have same URL for a record.
Both the entities are connected with inverse relation ship. And the relation ship is "delete->Cascaded"
What I want: If I remove a record in LatestData, I want the record with same URL in LatestDetailedData must also be deleted.
How?
If I am understanding you correctly, you are using a relationship and it has an inverse. If that is the case then when you delete one then Core Data will automatically delete the other and you don't need to do anything extra.
What are you seeing that suggests that is not happening?
Update
Since you are using multiple threads, are you using one NSManagedObjectContext per thread? If so, are you updating all of the threads when a save occurs? I suspect one of those two is not occurring and therefore causing your issue.
when you create the entities you need to create the relationship too
LatestDetailedData * entity2 = [[NSEntityDescription insertNewObjectForEntityForName:#"LatestDetailedData" inManagedObjectContext:context];
entity1.lastestdetail=entity2;
if you are just relying on a URL field, then thats bad practice. Set up the relationship in coredata and the cascaded deletes will take care of themselves.