An Author has multiple Books, both of which are NSManagedObjects modeled as a one-to-many relationship using Core Data. 20% of the time I just need to know how many books an author has written, so I check author.books.
40% of the time I need this data by order of date published, and 40% of the time I need it ordered by title. Multiple classes will want to access these ordered lists.
Question 1
Is it reasonable to add two additional methods to Author : NSManagedObject? Since I need to request them from multiple places, it seems smarter than sorting the NSSet each time in the class making the request. I.e:
#property NSSet *books; //core data generated - just returns the unordered set
- (NSArray *)booksByDate //applies an NSSortDescriptor to self.books, returns an NSArray
- (NSArray *)booksByTitle //applies an NSSortDescriptor to self.books, returns an NSArray
Question 2
Using the NSSortDescriptor has proven expensive, with an impact on UI performance. Ideally, I would like to try using the new(ish) NSOrderedSet to model the relationship as ordered, to see if there is a performance benefit. But I can't really pick which way to order the relationship, since whichever I choose (by date or by title) will be non-optimal 40& of the time. Not to mention that I may want to add more sorted variants later.
Is there some way I can have the best of both worlds, and store the relationship 3 times in my Core Data model? Once for the unordered relationship (NSSet), and once each for the ordered relationships (NSOrderedSet). I would only consider this if keeping all three properties in line with each other could be automatic - perhaps by tweaking how the NSManagedObject add/deletes/updates its Books. For example, I would like to somehow customize author.addBook to also insert the same book (in the correct location) into author.booksByDate and author.booksByTitle. And probably hide the
Is something like this possible? Advised? Remember, my main goal is to speed up retrieval of the ordered lists - I am willing to sacrifice write times for inserts/updates/deletes.
I would suggest to try to do the sorting when making the request for the sorted books. If you are presenting this list on a UITableView or a similar interface element, you can use NSFetchedResultsController and its cache system to have your list of sorted books cache. This means that when you try to access the books sorted by dates/titles, the calculation to determine the order of the books is already cached, and your list will be generated faster. I offered a similar solution to a similar question here.
Related
Using Core Data, I have two entities that have many-to-many relationships. So:
Class A <<---->> Class B
Both relationships are set up as 'ordered' so I can track they're order in a UITableView. That works fine, no problem.
I am about to try and implement iCloud with this Core Data model, and find out that iCloud doesn't support ordered relationships, so I need to reimplement the ordering somehow.
I've done this with another entity that has a one-to-many relationship with no problem, I add an 'order' attribute to the entity and store it's order information there. But with a many-to-many relationship I need an unknown number of order attributes.
I can think of two solutions, neither of which seem ideal to me so maybe I'm missing something;
Option 1. I add an intermediary entity. This entity has a one-to-many relationship with both entities like so:
Class A <<--> Class C <-->> Class B
That means I can have the single order attribute in this helper entity.
Option 2. Instead of an order attribute that stores a single order number, I store a dictionary that I can store as many order numbers as I need, probably with the corresponding object (ID?) as the key and the order number as the value.
I'm not necessarily looking for any code so any thoughts or suggestions would be appreciated.
I think your option 1, employing a "join table" with an order attribute is the most feasible solution for this problem. Indeed, this has been done many times in the past. This is exactly the case for which you would use a join table in Core Data although the framework already gives you many-to-many relationships: if you want to store information about the relationship itself, which is precisely your case. Often these are timestamps, in your case it is a sequence number.
You state: "...solutions, neither of which seem ideal to me". To me, the above seems indeed "ideal". I have used this scheme repeatedly with great performance and maintainability.
The only problem (though it is the same as with a to-one relationship) is that when inserting an item out of sequence you have to update many entities to get the order right. That seems cumbersome and could potentially harm performance. In practice, however, it is quite manageable and performs rather well.
NB: As for arrays or dictionaries to be stored with the entity to keep track of ordering information: this is possible via so-called "transformable" attributes, but the overhead is daunting. These attributes have to be serialized and deserialized, and in order to retrieve one sequence number you have to get all of them. Hardly an attractive design choice.
Before we had ordered relationships for more than 10 years, everyone used a "helper" entity. So that is the thing that you should do.
Additional note 1: This is no "helper" entity. It is a entity that models a fact in your model. In my books I always had the same example:
You have a group entity with members. Every member can belong to many groups. The "helper" entity is nothing else than membership.
Additional note 2: It is hard to synchronize such an ordered relationship. This is why it is not done automatically. However, you have to do it. Since CD and synchronizing is no fun, CD and synchronizing a model with ordered relationship is less than no fun.
So I am basically trying to select the entire object, for the first 10 objects ordered by the # of occurrences of a specific attribute in a many-to-one relationship.
Essentially in the one table I have an 'id' attribute that maps to another table. There can be any number of reoccurring id's and I want to get the object for whichever 10 occur most often.
I can handle that fine in sql but don't know how to implement the equivelent in core data?
Heres what I got in sql:
SELECT *, count(id) AS count FROM ____ ORDER BY count DESC LIMIT 0,10
Thanks a lot for all the help everyone! It's much appreciated
I'm having a hard time understanding whether I understand the question correctly, or what your expected behavior is going to be re: sorting of the results. For example, if count("some_specific_id") > 10, then which 10 objects do you want back? Does it matter?
That question aside, I'm not sure you're going to be able to do this easily or efficiently.
Given (as I understand it):
You have a relationship between Entities Foo and Bar. Foo.bar is a to-one relationship with Bar, and Bar.foo is a to-many relationship with Foo.
You want 10 Foo objects, the ones that match your SQL statement.
Here's one way to approach it:
Fetch all of your Bar entities.
Sort that array by "foo.#count", descending.
Start enumerating over the sorted Bar array, and for each object, grab the Foo objects from its NSSet property named foo, until you have 10 of them.
I wasn't able to find any way through Apple's documentation to do this without fetching all of the Bar entities. With more information about your particular Entities you might be able to figure something smarter out. Other suggestions floating around said that if you really want to know the count of objects on the Bar->Foo relationship, maintain that in a separate property. Then you could do a fetch of Bar sorted by fooCount, and limited to 10, since that would be the upper limit needed to find 10 Foo objects.
I'm currently writing my first project using core data, and am having trouble working out how to query the relationship between some of my data.
In sql language, i have a Country table, which joins to a CountryLink M-M table containing the following fields:
countryId1
countryId2
bearing
What would be the correct way to model this in Core Data?
So far i have set up a single Country entity and a CountryLink entity (containing only a bearing field) and have added two 1-to-Many relationships from Country to CountryLink ('CountryLink1' and 'CountryLink2').
I've run the project and looked at the Sqlite db structure produced by Core Data (found here, using this sqlite gui), and the M-M join table seems correct (it contains the bearing, CountryLink1 and CountryLink2 fields), but i'm not sure how i would go about carrying out a fetch request for a single Country NSManagedObject to return an array of related Countries and their bearings?
Any help or related links would be much appreciated.
Thanks, Ted
First a word of warning:
Core Data is not SQL. Entities are not tables. Objects are not rows. Columns are not attributes. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. Trying to think of Core Data in SQL terms will cause you to completely misunderstand Core Data and result in much grief and wasted time.
See the Tequilla advice
Now, forgetting SQL and thinking in object graphs, your entities would look something like this:
Country{
someAttribute:string // or whatever
countryLinks<-->>CountryLink.country
}
CountryLink{
countryID1:string // or whatever
countryID2:string // or whatever
country<<-->Country.countryLinks
}
As you add Country and CountryLink objects you add them to the relationships as needed. Then to find CountryLink objects related to a specific Country object, you would perform a fetch on the Country entity for Country objects matching some criteria. Once you have that object, you simply ask it for the CountryLink objects in its countryLinks relationship. And your done.
The important thing to remember here is that entities in combination with managedObjects are intended to model real-world objects, conditions or events and the relationship between the same. e.g. a person and his cars. SQL doesn't really model or simulate, it just stores.
My application is CoreData based but they may be a common theory for all relational databases:
I have a Output-Input to-many relationship in my model. There are potentially an unlimited number of links under this relationship for each entity. What is the best way to identify a specific input or output?
The only way I have achieved this so far is to place an intermediate entity in the relationship that can hold an output and input name. Then an entity can cycle through its inputs/outputs to find the right relationship when required. Is there a better way?
Effectively I am trying to provide a generic entity that can have any number of relationships with other generic entity.
Apologies if my description isn't the clearest.
Edit in response to the answer below:
Firstly thank you for your response. I certainly have a two-way too-many relationship in mind. But if a widget has 2 other widgets linked to its Inputs relationship what is the best way of determining which input is supplying, say, 'Age' or 'Years Service' when both may have this property but I'm only interested in a specific value from each?
I'm as confused as Joshua - which tells me that it may be that you haven't got a clear picture of what you're trying to achieve or that it is somewhat complex (both?).
My best guess is that you have something like:
Entity Widget
Attributes:
identifier
Relationships
outputWidgets <<->> Widget
inputWidgets <<->> Widget
(where as per standard a ->> is a to-many relationship and <<->> is a to-many relationship with a to-many reverse relationship).
So each widget will be storing the set of widgets that it has as outputs and the set of widgets it has as inputs.
Thus a specific widget maintains a set of inputWidgets and outputWidgets. Each of these relationships is also reversed so you can - for any of the widgets in the input or output - see that your widget is in their list of inputs or outputs.
This is bloody ugly though.
I think your question is how to achieve the above while labelling a relationship. You mention you want to have a string identifier (unique?) for each relationship.
You could do this via:
Where you create a new widgetNamedRelationship for each double sided relationship. Note that I'm assuming that every relationship is double sided.
Then for each widget you have a set of named inputs and named outputs. This also allows for widgets to be attached to themselves but only of there are separate input and output busses.
So then for your example "age" in your implementation class for Widget instance called aWidget you'd have something like:
NSPredicate *agePredicate = [NSPredicate predicateWithFormat:#"name='age'"];
NSSet *ageInputs = [aWidget.inputs filteredSetUsingPredicate:agePredicate];
Have I understood the question?
There really is no better way if you want to be able to take full advantage of the conveniences of fast and efficient in-store querying. It's unclear what you're asking in your additional comments, which I suppose is why you haven't gotten any answers yet.
Keep in mind Core Data supports many-to-many relationships without a "join table."
If Widget has many Inputs or Outputs (which I suspect could be the same entity), then a many-to-many, two-way relationship (a relationship with an inverse, in Core Data parlance) between Widget and Input is all you need. Then all you need to do is see if your Input instance is in the Widget instance's -inputs or if a Widget instance is in the Input instance's -widgets.
Is that what you were looking for? If not, please try to clarify your question (by editing it, not by appending comments :-)).
I'm in the middle of writing some Cocoa classes to parse ID3 tags from MP3 files. To make them as easy to use as possible, I'm allowing the option to request a tag by the actual ID3 frame id ("TCON", "TPE1", "TALB", etc.) or an equivalent word/phrase ("genre", "artist", "album", etc.)
To store this data, currently I have a reference class which returns an NSDictionary with the frame id's as keys, and word/phrases as objects. As I need to look up definitions in both directions, currently I have a second method which returns the dictionary 'switched round', so the words/phrases are the keys.
My question is whether there is a better way to represent this data. Ideally there would be something similar to NSDictionary, the difference being that both the keys and the values must be unique, and you could look up both an "objectForKey:" and a "keyForObject:"
I could write a class for this myself, but I may lose some of the efficiency from hash tables as described in the NSDictionary documentation... also I'd rather keep the number of classes as low as possible in the overall implementation.
Any ideas? Cheers.
Funny you should ask this...
Quinn Taylor, the author of the CHDataStructures framework just added a CHBidirectionalDictionary to the framework last week. It allows you to find objects by key, and find keys by object. It's basically a wrapper around two mutable dictionaries, so you're guaranteed the same lookup time as with a regular dictionary.
The only caveat is that both the object and key must both conform to the NSCopying protocol.