Just wondering whether there is a good way to upsert items in a CoreData db?
Or is there a way for me to consider a CoreData db as a set?
I mean, if I insert an item into the db and if there is already an identical redundant item there, the db ignores it. Any way to conveniently do it? or I have to query each time when I insert in order to avoid redundancy?
I recently read this article
https://www.upbeat.it/upsert-in-core-data/
Basically, first create a constraint on the name, then you specify the TrumpMergePolicy in the Core Data context.
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
No - Core Data doesn't have a way of knowing how you consider an item "identical" or "redundant." The definitions of those words can change with almost every entity you create - for example, departments in a business might have unique names, but multiple people can have the same name (and frequently do).
You can take advantage of Core Data's querying power, however, and do a quick query with an NSPredicate to find out whether a record with your chosen identifier already exists. You might factor this query out to its own method (perhaps on your managed object subclass) so that you can call it conveniently.
Related
Im sitting with this issue bugging me. I have core data working fine, but when it fetches, in my case, the users, they come back in different orders. Normally would use the standard unique identifier, but core data doesn't have this. So....
Do I manually create an ID entity_property and assign it incrementally, or is the "object id" being made in incremental order; incremented maybe by 1, or just random IDs? hence making me able to use object id.
My goal is to get my fetched array in the same order the users was inserted.
Thanks
You'll need your own technique for generating the unique ID. Run that code in your NSManagedObject subclass's -awakeFromInsert, which is called once, when the object is inserted into the datastore. You can add a timestamp, or the value of an incrementing counter.
There's no built-in support for an autoincrement ID. You'll need a class variable, and increment that yourself in -awakeFromInsert. You'll also have to persist that value across launches, either as its own Entity or within the persistent store's metadata.
You might benefit from using an ordered relationship, if those users have a one-to-many relationship with some other entity.
The NSManagedObjectID is unique within the store, but will change when the NSManagedObjectContext is saved (and the NSMOID goes from temporary to permanent). No promises are made about its sequence or pattern of construction. And it can change during a managed object model migration. So don't depend on it for anything you need to control.
core data does not return ORDERED data. so, if your data is "string" or "date" type then you can simply sort your data by ascending/descending after fetching from code-data.
I do have some JSON file http://jsonblob.com/530664b3e4b0237f7f82bdfa I am pulling from forecast.io.
I am little confused how I should be creating my CoreData entities and relationships.
In below setup, I made my Location entity as the parent entity and created a separate entity for Currently, Minutely, Hourly, Daily. However I have decided it's best to hold all the information regarding the weather data in one entity, so I created a Data table for that purpose and tied it to Daily and Currently in the image below.
Before going further, I paused and would like to get a second opinion on it. Is this a valid way of going forward with this?
EDIT: Based on Wain's response I changed my model to this
Currently Minutely and Hourly add little value as they don't have any attributes or relationships. It's also generally easier to add a type attribute rather than having a number of sub entities because you can easily filter the type using a predicate while doing a fetch. If you're going to add more in the future then there could be a case for keeping sub entities.
Once the entities are trimmed down then you only have a Location and Data with a relationship. You should make that relationship bi-directional so that Core Data can manage the data store contents better. (this applies to all relationships, even if you keep the sub entities you already have).
Other than that, fine :-)
Is it possible to restrict a Core Data entry to a single attribute? For example, let's say I have this entity:
Entity
Attribute: name
and there are multiple Entity objects that can be added to the database via a one-to-many relationship. Can I restrict the data entries so that only Entity with different name attributes can be added? I don't want to query the data base every time something is added, because that would cause a performance impact when the database gets larger.
Thanks!
No, you can't.
For now I would have the following ideas.
1 - If the attribute is a string, you should make it as a canonical form (a plain text without accents, etc.). Then you can search with predicates like startsWith or endsWith.
2 - You could add another attribute in entity that you use as a hash value. That hash will be generated when you insert a new object. When you insert a new value, you will check against value.
3 - Indexing the attribute to improve performances.
Core Date cannot check automatically for duplicate values, so you have to check first
if an object with a given value exists before inserting a new one.
If you have to insert many objects, then it is more efficient to fetch all objects having
values from the new list first instead of many fetch requests.
This is described in "Implementing Find-or-Create Efficiently" in the "Core Data Programming Guide".
I have an entity (Order) that has a to-many relationship with an entity Item, which has a to-many relationship with an entity Note. If the price changes for a Note, or a Note is added, the 'price' attribute for the associated Order must update.
Right now, my solution is to have all Order objects sign up for NSManagedObjectContextDidChange notifications, and check all the inserted/changed objects to see if any of those objects is one of the Order's Item's Notes. However, this is very inefficient and hacky, and is leading to a few more performance issues that can be optimized away, but I'm starting to realize that my solution is what's faulty, not necessarily the issues.
So, what's the best way to do this?
EDIT: To answer the questions brought up by Rog: I'm looking to propagate the changes to model data, which are observed by view controllers via KVO. The problem I'm noticing is, if the price of a Note related to an Item is adjusted, there's no facility to account for this in Core Data. If I use keyPathsForAffectingPrice on Item, and return "notes", that only accounts for if notes are inserted/deleted, not if the Note price is adjusted.
If this wasn't Core Data, I'd write my own accessor for note price to just say [self.item willChangeValueForKey:#"price"], self.price = x, [self.item didChangeValueForKey:#"price"]; but that isn't possible since I can't do custom accessors in Core Data, right?
We problably need more details about your code to be able to help - i.e. are you looking at ways to propagate changes to your model data or to the UI?
Are you using a fetchedResultsController at the moment?
The way I see it, if your Order contains Items and the Items contain Notes, any updates to your "child" attributes will be effective immediately (provided you have your reverse relationships setup properly).
Then if you're looking at ways to updating your UI accordingly, then we need to know how you are currently fetching and populating your views with your Coredata entities.
What I'm trying to do is ensure entities in my graph are unique. For example, no two users should have the same social security number.
The two solutions I've seen out there are:
1) index your entities and search for matching entities using predicates prior to creating new objects
2) Create an in-memory dictionary for each entity unique attribute.
iConfess: I'm coming from a relational database world. I'm user to primary keys.
What is the best practice for what I'm trying to do.
I'd go with choice 1: "index your entities and search for matching entities using predicates prior to creating new object". It just seems to me that going with an in-memory dictionary requires that you would be (I'm assuming) duplicating content that would need to be maintained, thus creating opportunities for error, and has the potential of bloating to something larger than originally expected.
There could be a speed issue—querying indexed core data vs. querying a dictionary—but that could be so niggling as to be moot as I've had no issues with Core Data's speed so far.