Manage Compound Primary Key in Core Data - ios

I want to create compound unique key in core-data, as actual primary key in core-data is ObjectId. Please let me know, how could we achieve the same.
Updated Question:
I am having an entity which is working as a template. And that template is being getting created on server with particular combinations.
Like Entity Name : E
and there are 4 attributes A, B, C, D.
Now the entity is unique with following combination
A1-B1-C1-D1
A1-B2-C1-D1
....
So actually it is permutation combination of multiple attributes to create a uniqueness.
Now I want to detect these uniqueness during updating the records.

ObjectID is NOT the primary key. There is no primary key in Core Data.
Core Data is NOT a database. Treating it like a database in your designs will cause issues. Core Data is an object graph that can persist to disk and one of the formats that it can persist to is a database. Treat it like an object graph first and foremost.
The ability to have a unique ID for duplicate detection was added in iOS 9 and OS X 10.11. Review the WWDC video from 2015 to understand those changes.
Update
Even after your update my answer is still accurate. In iOS 9 they added the ability to define a unique id across properties that will aid in the update/insert problem. Watch the 2015 WWDC video for details on this feature.
If you are aiming for something older than iOS 9 then, no; there is no feature in Core Data that solves this issue for you and you will need to solve it yourself. This is a part of the classic "insert vs. update" problem that all persistence layers face.
The solution is to create a list of IDs and then fetch all objects that have those identifiers then iterate over what you are processing and use the fetched list to determine if you are going to need to insert or not.
Updating to iOS 9 and using the new API is easier.

Related

Deleting entity from core data

After making a rough version of my app, I am now looking to make the finalised version which is better and has many improvements. This involves changing the attributes in the entity holding the timers.
Having put the app on TestFlight already, some of the downloads will have data stored already. I am going to delete the current entity and make a new one. Will this cause any problems if data is already stored for the attributes within the entity that is going to be deleted?
IMPORTANT: I do not want to keep any of the data in the entity to delete and I want to delete it all, so when users update all their data will be gone (this is fine as I distributed it only to people I know e.g. family/friends), who have given some feedback.
Any help is much appreciated. Thanks in advance.
CoreData is very pedantic. Once a store has been created based on a data model, you cannot use it with a different model unless you do some kind of migration. Different in this case means almost any change to the model. Certainly changing the attributes for an entity, or adding a new entity, will be sufficient for CoreData to throw an exception if you try to open the existing store with the new model.
If you want to preserve the data in the existing store, you would have to do a migration, but since you do not want to preserve that data, it will be easier to delete the store when the new version of your app is first run, and let CoreData create a new store using the new model.

How to avoid duplicated records in core data - ios

I'm new in iOS, Swift. My application has one entity named "Category" in a relationship to many entities named "Movies".
"Movies" entities are changing, according to data that I get from a url. I'm looking for a way not to have duplicated movies records in each category, and I can't think of an easy way to do it.
Core-data does not have a built in way to ensure uniqueness. You have to manage that yourself. But it is not that hard. Before every insert/update do a fetch - if it does not exist then create it, it if already exists then update it. If you are updating many at a time (for example from a network request that has updates for many entities) then fetch all of then in a single fetch request and then create or update as needed.
Generally these fetches are done using uniqueIds for each entity. If you don't have any uniqueId for you entities then you have a deeper problem than core data. You could have two movies with the same name, or one movie that has different names. If you don't have anything that says the same, then you fundamentally don't have any way to know if you need to make another entity or update an existing one. It is possible that you can use the movie name, but I would not recommend that. I suggest that you look closer at your server api and see if there is a uniqueId that is served, and if there is none then you have to have it fixed by the server team.

Ensembles and Core Data Light Migration

I am currently doing some tests with Ensembles, specifically testing Core Data light migration.
My current configuration is as follow:
Device-A running my app with data model 1
Device-B running my app with data model 2
data model 2 is based on data model 1 with one additional string property, which is optional
My scenario is as follow:
At the beginning, running my app with data model 1 on both Device-A, and Device-B, everything synced fine using Ensembles (iCloud configuration)
On Device-B, install and run my updated app using data model 2
On Device-A, keep running my old app using data model 1, and add a new record
The result: the new record added on Device-A is uploaded to iCloud and then synced to device-B
My question: can I configure Ensembles to prevent it from uploading changes to iCloud in case that related data model is not the latest one? (i.e. in my case, Device-A uploads an object based on data model 1 while iCloud is already based on data model 2)
Thanks in advance!
UPDATE 1:
Drew, thank you very much for your answer. I definitely agree that uploads can't (and probably shouldn't) be prevented as Ensembles is a decentralised, peer-to-peer system.
In the ideal case, I would like that the device with the new data model will ignore data that is based on the old data model. (in a similar way to the existing behavior where the device with the old data model will ignore any data based on the new data model). Is that supported?
If not, please consider the following scenario as an example:
The old data model has an entity called 'Book' with two properties: title, and author (both fields are non optional)
The new data model has a new optional property called titleFirstLetter that should hold the first letter of the title field.
Currently, when Ensembles is not involved, I have full control when saving new NSManagedObject to the persistence store. Therefore, the updated code of my app which responsible for adding a new book, will make sure to extract the first letter from the title field and save it to the new titleFirstLetter property. (i.e. a book titled Catch-22 will have C in the titleFirstLetter property when book is saved).
In addition, when light migration occurs on the core data stack, I detect that, and perform a one-time procedure where I iterate all existing books in the database, and set the titleFirstLetter according to the title value. From this point and on, the database is consistent and valid, while the new code will ensure that future books added to the database will keep database valid.
Regarding Ensembles, if I don't have any control on old data coming from devices with older data model, how can I fill the new property of titleFirstLetter, if my code is never being called?
Thank you for your kind assistance!
You can't prevent it, no. Ensembles is a decentralised, peer-to-peer system. There is really no way for one device to know the current state of another device, so you couldn't prevent an upload.
The updated device should be capable of handling the old data from the other device. The device with the old model will ignore any data based on the new model, until it too is updated. Then it will merge all of that ignored data.
It is best to avoid migrations where possible, and stick to simple stuff like adding properties or entities, rather than tricky refactors. If you need to make a lot of changes, consider simply starting with a new ensemble (e.g. change the ensembles identifier).

Store and retrieve unique identifier from Core Data

iOS newb building an app to work with a website. Ultimately, I want to keep the app and backend on the website in sync.
Photos are saved on the website using the ID of the item. For the app, I would also like to save the photo with a unique number linked to the item.
On the website, the id of each item is simply the auto incremented number in a MYSQL table.
My understanding is autoincrementation is impossible in Core Data but it does create unique identifiers for each managed object.
How would I get and store this number in the core data database at the time the item is created for later retrieval?
Alternatively has anyone discovered a way to auto-increment in core data so as to give items numbers that could be used for storing photos. It would be nice to have a similar naming scheme for photos created by the app and those created through the website.
There is no 'built in' solution for creating an auto-incrementing id in Core Data.
One important thing you should recognize is that Core Data is an object graph not a relational database. This is very important in understanding how you should approach design with Core Data.
Yes, Core Data does create unique identifiers for objects in the form of GUIDs - so it's not a number, but rather 32 hexadecimal digits (Globally unigue identifier).
You can write a method that will get the next number in a sequence for an entity, but Core Data will not do it for you.
You may find the information in this question useful: Set auto increment in Core data iOS. I would not attempt to use NSManagedObjectID. This value can change.
My suggestion is that you allow the MySQL database to assign the id's and simply store that id in a number property in the Core Data object. For items originating in the app leave the id property blank until it has been sent to the MySQL database for persistence. Then, retrieve the Id that the database assigned it and set it to the Core Data object's property.

Core Data server syncing

I have a dilemma regarding Core Data and syncing data with server.
I wrote an app which uses Core Data, don't use id attributes, everything is set with relationships. Most of data is being generated on device and should be sent to server as backup. On the other hand, there is some data that can be reused among users and I want to have control over it, i.e. modifying, deleting, adding.
Question
When sending data to server, what's prefered way of dealing with relationships? In my opinion, it would be very inefficient to think in terms of Core Data, sending all relation objects to server and then deal with them if they already exist on server. So, using uniqueId is obligatory? Generating ones on server which will be shared and others on devices? Is there any other approach?
Thank you.
Assuming that the server database works with foreign keys, one common solution is to introduce id attributes and set them to some invalid state for new objects. For example, for new relationships you could generate an arbitrary number of unique "invalid" ids by using negative integers. The server would have to then assign new (server-unique) ids and send them back to the client. Of course, when importing data from the server, you replace foreign keys with relationships.
So if you have potentially more than one device trying to modify data also used by other users or devices, the server will have to be part of the solution. Otherwise, you could just generate unique IDs so the server can store the relationships.

Resources