I am working on to use CoreData to save data of an object to an entity created in the datamodeld file.
In my scenario, I made a datamodeld called Product which represents an item available in the grocery store.
I have several categories for each type of products. For example, produce, dairy, meat, etc... If I save those products in the Product context, they will all be aggregated into one database and retrieving the data will be a hassle.
I'm wondering if it is possible to store my items into different databases of the Product context.
The only workaround I can think of is to create an entity for each categories which is a child of Product. I don't like this workaround because I am creating unnecessarily entities (every products in each categories have the same attributes).
By "product context", I guess you mean managedObjextContext? Your data is not saved in moc, you write data on moc and it's reflected persistent store.
You can use multiple moc to save the data of your app but be extra careful to syncronize the moc to moc on main thread.
I did something on the same lines that you are proposing as a work around. It worked out fine in my case.
Related
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.
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)
I have two persistent stores with objects that use the same model. I would like to open both stores in one context, but save the context to only a single store, and then safely delete one of the stores. I am in essence trying to merge the contents of two persistent stores into a single persistent store. Because the entities have relationships, I am finding this difficult.
From this answer:
If you do need to have relationships between the objects in both stores, or you really just want to have a single store, your best bet would be to create a second NSPersistentStoreCoordinator and a third, distinct persistent store to hold the merged object graph. You will need to write code to create copies of the objects in a managed object context attached to this second NSPersistentStoreCoordinator. You'll need to set up the same relationships among the copies that the original objects had, too, but how you go about doing this depends on your data model.
That makes it seem clear, except for the details of how, literally, to make copies of the objects for the new store. Is this a migration issue?
Ultimately, I used the following approach:
[migrator migrateStoreFromURL:[NSURL fileURLWithPath:incomingPath]
type:nil
options:nil
withMappingModel:managedObjectModel
toDestinationURL:[NSURL fileURLWithPath:finalPath]
destinationType:nil
destinationOptions:nil
error:&err];
[persistentStoreCoordinator removePersistentStore:[[persistentStoreCoordinator persistentStores]lastObject] error:&err];
The file at "incomingPath" was the store I imported, the file at "finalPath" the already-existent store that I wanted to merge into. Both stores were open in the same persistent coordinator, and both use the same object model. I then removed the incoming store and never looked at it again; I suppose I could have deleted it at the file system level.
For my particular data needs, I then fetched all the records, culled out the duplicates, and saved the context.
I publish this answer because as a core data newbie this simple migration solved the "can't save relationships to objects in different stores" problem non-intuitively.
I have two managedObjectContexts(MOC): a temporaryMOC and a persistedMOC. If I initialize an entity in the tempMOC and the user decides to save, I save and merge the changes into the persistedMOC and save. In which MOC are now those entities? If the user start a new file, there will be now two entities in the tempMOC?
The MOCs is only a scratchpad with which you can create, update, delete and retrieve NSManagedObjects.
If you've got two objects as a result of a save operation - it means you've mistakenly created two entities that are saved with the merge.
Could you show us the code in which you create an object?
This is a bit of a tricky one.
I have Document entities that are currently being imported into CoreData from a SQLite database on a background thread. There's a separate context for the background thread and I am batching the save at every 500 entries.
Saving the background thread context triggers a notification which grabs my main thread's contexts and performs a merge between the two.
Everything works as expected if I am only importing document entities.
My problem occurs when I try and establish a relationship between the current document being created, an another entity called briefcase.
This is what my import routine currently does:
Create Briefcase entity
Loops through SQLite database rows and creates Document entities for each row
Create the relationship between the document in the loop and the briefcase entity
At every 500 rows, I save & reset the context. This triggers a ContextSave notification which grabs the main thread and merges with the main thread's context.
This is where my issue is: after the save & reset above, my Briefcase entity gets merged with the main thread so when my loop continues, the next document entity created tries to associate itself with the briefcase, which is where I get a crash saying I can't establish relationships between objects on separate threads.
I know that if I remove the call to reset the context after saving it, everything works as expected but my memory footprint goes way up and it is not something I am prepared to accept.
So my question is:
Can you think of a way of keeping the Briefcase entity around (and valid) for the entire import process so I can continue to create the relationships?
My first thought was to create the briefcase entity without a context and then add it to the context once the whole process is finished. This didn't work very well (it crashed on creation).
Your thoughts are very much appreciated.
Rog
Answering my own question:
Create Briefcase entity
Loop through SQLite database rows and create Document entities for each row
Create the relationship between the document in the loop and the briefcase entity
At every 500 rows, save context & immediately store the objectID for Briefcase after saving
Now it's ok to reset the context
(Re)retrieve the briefcase instance using the objectID saved above and the existingObjectWithID:error: method
Loop continues...