CoreData doesn't keep the sequence while saveContext - ios

I am trying to insert data in CoreData. I have may records to insert, this should be all or none. So I am creating instance of NSManagedObject and inserting it to NSManagedObjectContext one by one.
When I call below method after inserting all records:
[_myManagedObjectContext saveContext:&error];
This method save all inserted records to persistent store. When I open the Sqlite file generated by core data, I found all the records inserted by my app.
Problem is the order is not same. e.g I inserted records based on serial number 1-100 in sequense, I am able to see random sequence in CoreData sqlite file.
I know that I should not worry about the entries on core data sqlite file I can always fetch records in sorted order using NSPredicate but I need to keep the sequence because in some circumstances I need to study the database file.
Can someone tell me what to do to let saveContext method save records in the same order those are inserted to context?

The only way to reliably maintain order of your objects is to add an additional attribute on the object, such as 'index', and then set the value once the object has been created. Use this object to sort the results when you retrieve them or use the index to retrieve the objects in the required order.

The easiest way is to implement the NSManagedObject subclass's awakeFromInsert method and set a date property to NSDate(). Now you have a sequence which is accurate to 10,000th of a second. When you need items in order, just sort by this date property.

Related

Swift - How to update objects in bulk with out iterating over a collection of realm objects

I have nearly a hundred thousand records in my realmDB and I want to re-calculate a particular property every time the user changes his device timezone based on the other property in the same table.
Example :
class Activity: Object {
// In UTC received from server
dynamic var effectiveDate: Date?
// Needs to be re-calculated everytime user launches the app based on `effectiveDate`
dynamic var effectiveDay: Date?
}
Assumption: I have 100,000 such activity records in my realm table called Activities
Also, realm states that applying KVC to a collection is a great way to update objects in bulk without the overhead of iterating over a collection while creating accessors for every item.
In my case instead of setting the same value for every record, I want to re-calculate the effectiveDay based on effectiveDate property for every record using KVC to avoid the overhead of iterations. Is it possible?
Short answer:
It is not possible without iterating over a collection of realm
objects.
Long answer:
The realm is a model class based database. It does not support any
query (Predicates or Filter mostly used to retrieve data with a specific condition) like SQLite means We can't update all record in a single query by using the realm. So answer of your question is pretty
straightforward, Without iterating we can not update the value.
You can improve performance if you want to change the value of some object.
Code:
let persons = realm.objects(Person.self).filter("id IN %#", ids)
try! realm.write {
persons.first?.setValue(true, forKeyPath: "isFirst")
// set each person's planet property to "Earth"
persons.setValue("Earth", forKeyPath: "planet")
}

iOS - Reorder Items in CoreData

I have a tableView and an array locationsArray. The locations array is filled on viewDidLoad from data in my CoreData.
I have implemented the reorder methods on the tableView and that works fine however I can't figure out how to save the reordered array back into CoreData. I've tried deleting everything in CoreData and just saving the new reorderedArray. Although this is obviously very costly resource wise it seems to just load the elements back into the array in a seemingly random order.
Is there an easy way to do this that I am missing or can you not store things in CoreData in a certain order?
Strictly saying, it is impossible to store objects in certain order. You can only set the order for retrieved objects
When you retrieve locationsArray from CoreData, you have no any guaranties about their order.
The only way - add field to your Managed Object that will be used to order your locations.
Than, on retrieval, you'll be able to use locationsArray = [locationsArray sortedArrayUsing<#WhateverYouNeed#>];.
You can, also, achieve this by using sortDescriptors property of NSFetchRequest. It will provide you with desired behaviour from the box. The only downside of it, that your NSSortDescriptor in that case cannot be defined by block, so if you ordering is using some complex approach, you'll need to sort the result with already fetched data
use the predicate to sort the array or after fetching the array from coredata sort it using
NSArray *sortedlocationarray = [filteredlocationarray sortedArrayUsingDescriptors:#[sortDescriptor]];
where filteredlocationarray is from coredata.

Is it possible to exclude the object with the latest date?

I have a Core Data Model with an Entity that has an attribute "creation Date"
What I'd like to do is to create a fetch request that has all objects but not the latest.
As the content of the Core Data store changes while the user looks at the data (i.e. a UITableView) I can not set a "latest Object" and use this for the NSPredicate.
So is there a way to create a format to exclude the data set with the latest date?
Yes, you can build your NSFetchRequest with the following settings:
Sort by date, descending order
Set the offset to 1
execute the fetch and it will skip the first record.
You can then load it into a NSFetchedResultsController if appropriate.
If you are displaying the results in a table view, you can manipulate the datasource to omit the last result. (You return count minus one in numberOfRowsInSection.) This should work perfectly well with a fetched results controller as well. Don't forget to also modify the delegate methods.
If you just need an array (not recommended), read into a mutable array and remove the first or last object (depending on sort order). When the data changes, just re-fetch and replace the array.

Is that possible to add a value in a core data fetch?

Suppose I have this core data structure:
code
name
address
value
is that possible to add 100 to value during the fetch? I mean, to receive a fetch results where all values are their values on the database + 100?
I know I can enumerate all results after and change the value but I am wondering if there is a way to do that while I fetch.
No, all a fetch can do is give you the literal contents of the persistent store. If you're fetching a managed object subclass you might consider adding a computed property as a category method that always returns the named field plus 100; if you're fetching dictionaries then you'll probably have to modify them yourself (which will be a hassle as they'll come back immutable).

Core Data constraint with "includesPropertyValues"

I would like to make a more efficient fetch on Core Data entities and I have a query.
I want to delete a large amount of records (millions).
My logic is:
fetch all records for the entity
delete all fetched records.
To improve fetching,
I set the following constraint:
fetch.includesPropertyValues = NO;
My question is: will the relationships (which are kept as properties in the managed objects) also be deleted?
Yes, if you delete a managed object, the relationship delete rules apply regardless of this flag.
With so many records you might also want to want to process the instances in batches. Use setFetchLimit: to get a subset of the instances, delete those, save changes, and repeat until no more instances are found.

Resources