I'm writing an iOS app which has store of person records, and needs to display lists them sorted in particular ways. There are a variable number of these orderings, and they are generated on the fly, but I would like them to be stored in the datastore. The SQL way to do this is to have a ListPositions table with a list name, an id into the persons table, and a sort key. Then, to display a particular list, I can select all list ListPositions with a given name, pull in the refer开发者_如何学JAVAenced persons, and sort on the sort key. Trying to do this in CoreDatat, however I run into problems. I am trying to do this using a schema like:
Person:
Name
DOB
etc...
positions -->> ListPosition
ListPosition:
listName
sortKey
person --> Person
Then, I can get all the Persons in a given list with the NSPredicate
[NSPredicate predicateWithFormat:@"ANY positions.listName like %@", someList];
This allows me to dynamically add lists against a large set of Persons. The problem is that I am unable to use the sortKey field of ListPosition to sort the Persons. What NSSortDescriptor will do this? And if it is not possible to sort a fetch on the property of one element of a to-many relationship, what is another way to get multiple, dynamic orderings in coredata? I am displaying the lists with a NSFetchedResultsController, so I can't put the lists together myself in memory. I need to do it with a single NSFetchRequest.
You're right-- following a to-many relationship returns an NSSet, which has no inherent sorting. To get sorted results there are a couple of options:
- Assuming that Person/ListPosition is a two-way relationship, do a new fetch request for ListPosition entities. Make the predicate match on the "person" relationship from ListPosition, which would look something like
[NSPredicate predicateWithFormat:@"person=%@", myPerson]
. Use whatever sort descriptor you need on the fetch request. - Follow the relationship as you're doing, which gives you an NSSet. Then use NSSet's
-sortedArrayUsingDescriptors:
method to convert that to a sorted array.
I think the best approach in this case would be to fetch on ListPosition entity instead. Add the sort Descriptor for sortKey (it would work in this case because the fetch request is on ListPosition entity) and prefetch the Person associated with the the list name using setRelationshipKeyPathsForPrefetching for "person" on the fetch request.
[NSPredicate predicateWithFormat:@"listName like %@", someList];
If I understand your model correctly, each Person
has one ListPosition
for each list in which it participates. Let's say we have acsending list by their names, so X people have X list positions with the same listName
and sortKey
.
I would create entity List
, that would contain the sortKey
attribute and then use it in sort descriptor.
entity List:
- sortKey : string
- ascending : bool
Create sort descriptor and use it in fetch request:
[NSSortDescriptor sortDescriptorWithKey:chosenList.sortKey ascending:chosenList.ascending];
Then you may have as many Lists as you want and you can easily use its sort key to sort all people.
If you want to store the positions in database (you didn't mention attribute index
in your ListPosition
, or anything similar), you can create “joint entity”:
entity PersonInList:
- index : integer
- person -> Person
- list –> List
Another idea is having ordered set of Person
objects directly in List
entity.
Get the ListPosition (it will come as a NSMutableSet). Then do a sort on the Set, like this:
NSMutableSet *positionsSet = [personEntity mutableSetValueForKey:@"positions"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"yourSortKey" ascending:NO];
NSArray *positionsSortedSet = [positionsSet sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
That will give you a sorted out array according to your key.
I usually add an index field (type NSNumber) to an entity. It's very easy to calculate index in adding item. just by
object.index = person.positions.count
so, actually you don't need positions field but positions relationship. connect person entity to ListPosition entity would be enough.
精彩评论