I'm using CoreData in my project and I'm thinking about unique fields and creating objects or updating them if they are already existing.
UseCase:
Get JSON from Server
Map JSON to Object
Save to CoreData
What I want to do is:
Get JSON from Server
Map JSON to Object
Does the object already exists (Unique field is unique identifier for object)
If YES
Get object
Update fields
If NO
Create object
Save to CoreData
Isn't that a lot overhead for the solution? So every time I get an object I have to check the CoreData. Is there something that can do this handeled by CoreData internally?
Have a look a MagicalRecord it has built in maps from JSON to core data and will keep unique items unique.
Related
I wish to save a dictionary containing some Core Data objects (bunch of different entities). The objects also have quite a few relationships (and inverse relationships) defined. What would be the best way to go about it?
I tried using NSKeyedArchiver and writing to a file. While that works great, when trying to read from the file using NSKeyedUnarchiver, it fails on one of the classes with the error
-[SomeEntity initWithCoder:]: unrecognized selector sent to instance
EDIT - More details
I have a bunch of objects, each having properties based on which they can be filtered. The properties are in themselves Core Data entity objects since they have a complex structure.
I wish to save the filters the user has selected so that the next time they view the objects, the objects can be filtered as per their previous selection.
Say there are 3 filters, Filter A, B and C and each can have 5 different values. Now the user might select Filter A1, A2, B1 and C3 (or a different combination). My question, how do I save these selected filters (A1, A2, B1 and C3 in this case) using Core Data?
Let me see if I understand your question: You have a collection of managedObjects that are already saved in a context. They may already be persisted in the SQL database. You want to save that collection ALSO to another file for other purposes. You have already considered saving the information of this collection inside core-data in some way and have already rejected it. You have also considered simply saving the query generation tokens to save the state of the database as it currently is, but that also is not what you want. The point is to have a file that contains a copy of some of the managedObjects organized in a way that you can get the data back without using the SQL database that was already designed exactly for that purpose.
Solution 1: Turn each managed object in a dictionary.
You can get every attribute and every property of every object by getting a managed object's entity and then accessing the attributesByName and
relationshipsByName property of the entity. From there you make a simple loop to put each property into a dictionary. I also suggest you store the objectID and point to the objectID when encoding the relationships. Then replace the managedObject in your dictionary with dictionary that contains all the attributes and relationship. This new dictionary should be easy to archive and unarchive.
This make sure that the data when you unarchive is exactly how you left it. When you unarchive you will get a COPY of data and if the managed objects have changed in your database since then, you will get the OLD values. Also these copies are not core-data object because they are unconnected to a managed Object Context.
Solution 2: Just save the Managed Object's ObjectId.
Replace every managed object in your collection with the object's objectId. This dictionary can be easily archived. When you unarchive it replace every objectId with a core data object (if found) using existingObjectWithID: on the context. If entities have been deleted then you won't get them back. If entities have changed then you will get the NEW values.
Solution 3: Don't do any of this
It seems to me that you may not be aware core-data are already saved in a database. If you have some collection of managedObjects, you should be able to recreated it from your database. If you aren't able to, then you should add properties and/or relationships that will allow you to so.
Try like this :
ARCHIVE :
NSDictionary *yourDictData = [NSDictionary dictionaryWithObject:json forKey:#"key"]; // This is for example. Here you have to replace ur dictionary
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:yourDictData];
UNARCHIVE :
NSDictionary *myData = [NSKeyedUnarchiver unarchiveObjectWithData:yourDictData];
I am developing an app in Swift which fetches JSON records from API, converts it into NSArray and reloads in UITableView.
I need to map the NSArray with CoreData and, when making a new request to API, if there is new child added in JSON response, I've to store only that child in CoreData. I.E. I have to avoid repetition of values of NSArray in CoreData.
I found few solution as "using unique constraint for data models" and "HyperSync and DATAStack" but I am not able to do so. Do I have to implement a module to check through all the records ?
If your objects in JSON have some identification, e.g. [ { "id" : 4, ...} ...], then you should store these "id" values in your CoreData objects, and try fetching already existing ones during mapping before creating new ones.
If there is no identification or unique fields in JSON objects, then your task is not resolvable.
E.g. RestKit framework does all that for you automatically, you have to configure only mapping and identificationAttributes.
When I GET the server, I check the attribute "objectID" on each object, and if the objectID is already in the local store, I don't store the object.
Question: What's the approach if the "objectID" exists, but its other attributes have changed and thus the entire object should be replaced with the new object? There is an other attribute called "lastModified" that will change. Do I compare against both "objectID" and "lastModified"?
Generally, yes, compare the id and then check the modified date. Try not to replace the object though, instead, pass the new object to the existing object and have it update itself (then throw away the new object).
Note that if you were using Core Data then RestKit could handle this for you using unique identifier (so it can find the existing objects and update them during the mapping process).
I have a question about creating a database with core data.
In my app at first start I should parse some json to obtain some data to insert in core data db.
my json files are structured in this way: (I show only an element of my json)
[{"id":"s1",
"n":"Name hotel",
"id_loc":["l1","l2","l3","l4"],
"val":3,
"tel1":"12345678",
"tel2":"12345678",
"obj":
{"id":"o1",
"n":"Name",
"des":"description",
"flag":"red"}
}]
I understand that I can consider this as an entity in coredata and consider all element as attribute, it's clear.
Now you can see that inside my json there is an array "id_loc" and an object (or dictionary) "obj".
In core data what's the way to manage these two elements?
I suppose that "obj" can be managed as a new entity, and "id_loc", what's the way to set it in my core data DB?
Can you help me?
Thanks
For obj, it's as you suggest: create a new entity, and set up a relationship between the two entities.
For id_loc it depends on how you need to use the data.
If you just want to have that data available when you look up an instance (that is, you maybe display this data but don't ned to search for it), you can store the strings in an NSArray. Make the attribute transformable in the Core Data model editor, and Core Data will read/write the complete array.
If you need to look up data based on id_loc values (for example: Find every object where id_loc contains l3), the best approach is to create another entity to hold values of id_loc, and set up a to-many relationship to that new entity.
I am using the latest RestKit for iOS. I have a few different APIs that I want to map into the same CoreData Object. I am trying to hard code a value in field on the object that identifies which API the data came from.
Does anyone know if this is possible using the RKEntityMapping for RestKit?
You need to set your API field, which will store this value, to transient in your core data object. Next add block with setWillMapDeserializedResponseBlock: in which you add an appropriative indicator value to the mapping dictionary.