Core Data with multiple persistent stores - ios

I am trying to use multiple (two) persistent stores with Core Data for the first time.
It seems quite simple to add a store; but once this is done, how do I specify that a request to write (or read) some information to (or from) an entity has to be performed on one store or the other?
Some sample code would be welcome, but I can’t find anything on the net.

Fetches always cover all of the persistent stores managed by the coordinator.
When adding data, you can do either of the following:
Use configurations in your data model and when adding persistent stores. Configurations define named subsets of your model that contain some but not all entities. If an entity only exists in a configuration that's only used with one persistent store file, then new instances will automatically go to that store.
If the above doesn't work for your app, you'll need to call assignObject:toPersistentStore: to tell the managed object context which store to use.

Related

Core Data with both static pre-populated and dynamic user data

In my project I have pre-populated data in Core Data, ie. I have a sqlite file that's copied into user's folder on first launch, however I also have user data which user generates, in this case is there anyway I can use a single data model? I know I can create two models one static and one for user but just wondering if there's a better way.
Thanks!
update:
My concern is although it works for the first release, in subsequent releases if I need to update the static data, it would be a new sqlite file that's copied into user folder which will overwrite existing user data.
Question: [...] can I use a single data model?
Yes. There is the concept of Configurations with Core Data Models. You can learn about it here: NSManagedObjectModel. This allows you to partition one data model into several parts. For the use case described in the OP you want have two parts or configurations: "StaticData" and "UserData". "StaticData" holds entities and data that may change only with App updates (new releases). "UserData" holds user data. You need to design data and foreign keys accordingly in a manner that the entities of both data sets are "well linked" for the App's lifetime. (If you cannot ensure this from the beginning to the end you need to design additional data migration processing for each release).
Question/Use Case: Only update static data not overwrite user data.
Each "Configuration" (see 1.) will have a persistent core data store (SQLite file) for its own. For the use case specified the file with user data must not be excluded from the backup but the static data must be excluded from the backup. You can learn about how to exclude files and directories from backups here: NSURLIsExcludedFromBackupKey. After a new release the empty user data will be overwritten with the user data from the backup.

Copy records between persistent stores in core data?

I want to copy data from one store to an other. Destination persistent store could already have records. Is it any easier way, than manually go though all the records and insert into the new context and save?
If you want to copy all of the data, you can use migratePersistentStore:toURL:options:withType:error:, which is a method on NSPersistentStoreCoordinator. This will effectively copy the entire persistent store to a new persistent store file. Some things to be aware of:
Despite the name, this method has nothing at all to do with model versioning. Both use the word "migrate" but they're different processes.
You should be sure that you have saved all outstanding changes before attempting this.
After doing this, the store that you're migrating from is removed from the coordinator-- which means that
Any existing references to managed objects are now invalid. You should re-fetch them.
If you continue using the coordinator, you're using the new store file.
If you don't want to copy all of the data, you need to do it "by hand", fetching objects from the old store and creating equivalent objects in the new one.

Save data in two persistent stores

I am having an app where there is a search feature that does a network request. However uses the same model framework as the entire app.
This means that when the user searches for something I need to create managed objects from the found data, save them and display them. However this messes up old records with the user recent data.
I would ideally like to save the managed objects found in the search in a separate in-memory persistent store so it doesn't make disorder in the main data.
I haven't done something like this before so what is the best way to approach it?
Thank you!
As has been suggested by #stevesliva, you do not need to involve yourself into the complexities of maintaining multiple partially in-memory stores. The way to go here is to create a child context and fetch the online data into this context. Once you do not need the data any more, just discard the context.
If you decide to save the downloaded data, you can simply "push" the changes to the main context via save:. At that point you could make necessary adjustments to the data so they fit into the user data. Depending on your model, one feasible solution could be to create another attribute on one of the entities that marks linked objects as distinct from the user created objects.

iOS: DDL Commands during runtime

i want to add tables/columns to a database during runtime.
Currently I'm using Core Data.
I know that there's a possibility to do so in XCode (add new data model version), but I definitely can't use that way, because I receive the database schema from a web service.
Is there any good possibility to run ddl commands during runtime when using Core Data, or is it just possible with directly using sqlite (or a wrapper/ormapper)?
If it's better to use a wrapper/ormapper please give me some suggestions about which should be used in this case.
Workflow should be:
start app
check if database is up to date
if new version of schema is available from a web service do DDL commands
continue with app workflow
PS: Please no answers which describe alternatives modifying the schema with XCode!
Can you modify the Core Data model at run time? Yes...but, it probably won't work the way you want it to work.
Core Data's API makes it possible to construct or modify every detail of a data model at run time. Xcode's model editor is a convenience, but you could skip it and do everything in code if you wanted. For example, NSEntityDescription's properties attribute (which covers both attributes and relationships) is writeable. You could create a new NSAttributeDescription and update the entity's properties to contain it. Bang, you just added a new attribute to the entity. Similarly, NSManagedObjectModel's entities property is writeable, so you could create a new NSEntityDescription and add it to the model. That gives you a new entity, created at run time.
But, and it's a big one: you can only do this before you load the data store. Once you load your persistent store, altering the model will throw an exception. When Core Data loads a persistent store, it compares the model file to the model used in the store file. They must match, and you can't do anything to change this fact after loading the store. Once you load the store, the model is fixed.
What's more, even if you modify your model before loading the persistent store, you can only load persistent stores that match the current version of the model-- unless, that is, you also write code to migrate the persistent store to the new model. How hard that is depends on the nature of the changes. At a minimum then, you would need to make any changes before loading previously saved data, and then also arrange to do model migration to update the persistent store to use the new model.
With Core Data the model (schema) and data are stored separately and matched up when the store is loaded. That's not how SQLite works internally but it's the approach that Core Data enforces.

CoreData Update Database Leaving User Entries

First, Thank you for any help provided.
I have an iOS leveraging CoreData to retain various presentations, this data comes from a sqlite file and there is no server connection.
I will have to be able to provide App updates (via appstore), this update may add more data to the database.
The tricky part is that it can not simply overwrite the current database, there are a few user tables that I will not like touched.
Please provide any information I should consider when accomplishing this or any links are greatly appreciated.
Thank you.
Given your app has no server connection, you will have to rely on shipping data within the updated application itself. I would recommend using a plist file or define your own xml or json structure. You can then read this data to create/update core data nsmanagedobjects.
It looks like someone in the past was using plist->coredata on SO
Would you have relationships between user created data and shipped data?
If not, you might go the route of connecting two stored to the persistent store coordinator. The shipped store would be read-only. The store with user created data would be read-write. You can use this approach, too, if you have relationships between shipped and user-created objects, but it's a lot more complicated, since CoreData doesn't manage cross-store relationships for you, and you'll need to write your own logic (doable, but not straight forward).
If you need to have relationships between shipped and user-created objects, you can still ship a CoreData store. When the app launches for the first time (no user-created objects), you copy the store to the Documents folder and user this store to create your CoreData stack. User created objects will be added to this store. Once you have new 'shipped' objects (i.e. a new store in the app-bundle), you'll have to manually migrate that stores data into the store that the user has changed. You'll have to be able to find
(1) objects that need to be deleted
(2) objects that need to be updated (changed)
(3) objects that need to be added
If you mark your shipped objects with a special flag such that you can tell if it's a user created object or a shipped one, that would be doable. You also have to have some sort of ID to be able to tell which objects in the new store correspond to which ones in the existing (old) store.
You do not need to go the route of using plists. In fact, I'd recommend against it. You can easily open two stores at the same time. Either to use both stored, or just to migrate objects from one store to the other store.

Resources