efficient way to remove superfluous data from core data - ios

I read data from one of more remote files into coredata. If a remote file is changed the data in core data needs to be updated. For instance, assume one file is filled with departments, the other with employees.
As the company is restructured, one department is renamed and a second department without employees is deleted in the file. The employees file is not changed, so I only want to reread the file with departments. In my code I read the file, fetch the department from coredata and updates its name property. But since the second department is no longer in the file, I want to delete it from core data.
My pseudocode solution is as follows:
the department entity gets a hasChanged attribute
before reading from the file, all hasChanged attributes are set to false
if a department is present in the file, its hasChanged attribute is set to true
after the file is read, all departments with hasChanged attribute set to false are fetched and deleted
Somehow the seems not very efficient. Deleting all departments and building them a new seems also not very efficient, because core data will delete all employees with the departments and now I have to reread the employees (and probably all other files) also.
Is there a better way to approach this problem of data becoming superfluous? If you answer with code, swift is preferable.

First the delete rule should not be cascade - change it to nullify.
When you get new data from the server follow these steps:
fetch all of the entities that are effected. If you are updating departments - then fetch all the departments
store the results in a dictionary where the ID is the key.
Also store all the results in a mutable set called objectsToDelete
now iterate through all the data that you got from the server. lookup the department using the dictionary you made in step #2. If you find the object, then update it and remove it from the set you created in step #3. If you don't find the object then create it.
If there are any objects left in objectsToDelete then delete them
save the context.
It is the same principle for the employees. You match up the ones you already have using a dictionary, and delete the ones that don't get matched up.

Related

Remove or Add an attribute to CoreData at runtime programmatically

I have to create and remove attributes based on an api response in Objective C.
For example, Now my api response contains fields "facebook", "whatsapp" and "viber". But in future the reponse can add "youtube". Based on this response, I have to remove all the attributes and values of an entity "Social", and create Four attributes now and set values.
How to do that programmatically? Because the default *.xcdatamodeld file cant help me here, right?
Note: My project is in objective C.
The data model is mutable when the app starts-- you can completely build the model in code, and not use the model editor, for example. But as soon as you load a persistent store file, you must treat the model as fixed. Any changes after loading a persistent store will cause crashes. That means any changes would have to happen before calling either loadPersistentStores(completionHandler:) or addPersistentStore(with:completionHandler:).
Alexander's suggestion of optional attributes is a good one. If you need the model to be more dynamic, you would need to create a new related entity which would store the service name plus whatever information you need to save about the service. If you did this, your Social entity would have a to-many relationship to a new entity called something like Service. Service would have a string property called name that would have values like twitter, facebook, youtube, etc. It would also have whatever other attributes you need to save about the service.
You can create all 4 fields in advance and just make them optional and fill them depending on the server response. But you cannot add new attributes in runtime. Your *.xcdatamodeld file compiles into *.momd and it contains all the data to create tables in the DB since Core Data by default works with SQLite under the hood and it's a relational database management system.
To make attributes optional you should check that.
And then newly created objects contain nil as default values of object properties. So, in your case your "youtube" property of Social object will be just nil.

Core Data: Which record loads by default in core data if you do not specify which one?

I have a static table for settings where I want to pull some stuff from an entity in Core Data. The use case does not lend itself to a table of records as you usually see. Rather each row of the static table is really a field related to the user--as in a user profile. I have a feeling that in testing I may have created more than one record in the entity. I know there are programs that let you see the SQL lite database underneath, but my question assumes you do not have this tool and are relying just on Xcode.
My question is when you have more than one record in a Core Data entity/table, and you try to load data from the managed object context into a VC, one field into one element, what record is shown by default?
Related to this, if you don't know how many managed object or rows are in the database, is there anyway to specify which record you want since there are no auto ids as you would use in a traditional database?
The record that gets loaded from the fetch first. Depending on your sort that might be consistent or it might be random.

Coredata relationship breaks once the entity is updated

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.

IOS Core Data Cascade Delete Issues

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)

duplicate NSManagedObject

I am using CoreData in my app and i have a set of "Card" entities. A player can have more than one of the same card in his deck (it is still the same card pulled from the database but added two times to an array).
My problem occurs when I want to modify an aspect of one of the duplicate cards. They are all subclassed NSManagedObjects which have some custom properties on them (which are not saved onto the database). For example when I set one of the custom properties on one card in the array it is also changed in the other same card in the array because the entityForName:inManagedObjectContext: returns the same object and does not load a new one.
Basically what I need is that each time entityForName:inManagedObjectContext: is called I get a new instance of the same entity so that when I modify a custom property in one it is not also modified in the other. I have already tried using [entity copy] if the entity has already been created but it does not work.
Thank you in advance for your help!
Core Data is a persistent store, not a database. So it's reason detre is ensuring that you get exactly the same object out, no matter how many times you ask for it. Those aren't snapshots from the database as they might be if you wrote some custom SQL code, those are the actual live objects.
With that in mind, what you need to do is either configure your Core Data schema to match your logical schema — I guess you'd have, say, CardInstance, with a one-to-many relationship with Card, and you'd create CardInstances for when you pulled a card from the deck — or write some code to read from a fetched Card into a snapshot object, exactly as if you were working manually with SQL or whatever.

Resources