Sorting based on one of many related entities - core-data

Entity B (Book) has a one-to-many relationship with the entity D (Description). The idea is that a book has different descriptions for different languages.
I want to sort books based on their titles (D.title) for a given language (D.languageID)
If B had one-to-one relationship to D, I would do something like:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"d.title" ascending:YES];
Of course, you may say, the model does not prevent a book from having many descriptions with the same languageID. But in this case any (e.g. the first) description would be ok for me.
Is my model wrong? What's the best solution now?

This is logically not possible. If you have many objects B belonging to A, which B is the sort routine supposed to take?
For example you have the entity A "Parent" and the entity B "Child" and the attribute of B "dateOfBirth". You cannot sort all Parent objects according to the lowest birth date because if two different parents have two children each, it is possible that each of them has a child that is older than one of the other's.
Clear?

Related

Saving various core data entities of the same type with multiple different relationships?

I've been trying to debug this for 2 hours, have to sleep. First, I've searched and found many similar posts with they keywords: many entities same type and this one:
Core Data: inverse relationship for two relationships with same type
But to no avail. Here's what's happening:
I have a data model with two types. For example, I have a Person, and that person can have 4 lists of emails. The email type is its own thing, so I make the person store 4 distinct sets (relationships) to each list.
Basically, when I retrieve one set, it grabs all of them. All 4 lists are now 1, and it doesn't seem to matter how I set the inverses. Actually these changes somehow caused the entire thing to not save anything, all nil objects when downloaded. Previous to this, it worked fine (except for shoving all 4 lists into one set). All I updated was the data model for relationships. I may have exported the files in the wrong order, but do not know if that's related.
I simply can't find the keyword combination to find if someone's asked this before. I don't see how it wouldn't come up, what I'm doing is basic abstraction. I keep thinking I overlooked one box.
To summarize, I have a person, and person has 2 lists. I add them similar to this:
person.friendEmailsList = downloadedEmailsFromFriends;
person.businessEmailsList = downloadedBusinessEmails;
so later, I access person.friendEmailsList (using the correct core data call, of course), and instead of getting just friends, I get everything... friends, businesses everything
Any suggestions would be appreciated
There are two possible solutions.
First, you can use the approach you use. Just make sure that you also have corresponding reverse relationships from the other entity. So if you have 2 relationships to the same entity, that entity needs 2 distinct relationships back. E.g.
Person.friendsLists --->> List
Person.businessLists --->> List
List.friendPerson ---> Person
List.businessPerson ---> Person
The more flexible approach would be to have the list have an extra attribute type (could be a number as some kind of enum).
typedef enum {Friend = 1, Business } ListType;
You could put this into your List.h file. Now, to access just friend lists you can do this:
NSSet *friendList = [person.lists filteredSetUsingPredicate:
[NSPredicate predicateWithFormat:#"type = %#", #(Friend)]];
This might be a bit much to type, so you can simplify by putting an accessor method into your Person.m (declare it in .h):
-(NSSet*)friendsLists {
return [person.lists filteredSetUsingPredicate:
[NSPredicate predicateWithFormat:#"type = %#", #(Friend)]];
}
Now you can access the lists with the usual convenient person.friendsLists.

UML class aggregating to self

My group and I are making a program, where we have a tree structure. In this tree structure we have made it such that a category can contain it self. The program is based on your expenses, so an example could be:
You have bought 4 milk. The 4 items of milk are placed in the category "Milk". Each entry of milk has the price (along with other individual information) in another class which category aggregates.
The trick is that we want the category class to be able to contain it self, so:
The category "milk" is part of the category "Dairy Products", which in terms are part of the category "Groceries".
The reason we want it to be like that, is so we can move batches of products at the time. So if you want to move Milk to a category called "Morning Stuff" you wouldn't have to move every single one, but instead just the entire category.
The picture is how our current category class is modelled, but we were told we couldn't do it without much further explanation. Does UML allow this? If not, how can we model it with UML?
Yes, UML allows associations from a class to itself. Likewise aggregations and even compositions are allowed this way.
The image you posted shows an aggregation while from your description I would have chosen a composition (filled diamond): a category has one or no parent; a category is somewhat defined by its children; if a category gets deleted all children are deleted as well.
A longer comparison between aggregation and composition can be found here.
Yes it is allowed, but in most cases it is better to aggregate an abstraction (abstract class or interface) in order to preserve Polymorphism rather than the item its self; see the Composite Pattern for an example.
This is known as the Interface Segregation Principle and is one of the five SOLID principles

Core Data: inverse relationship for two relationships with same type

In my app Core Data model I have Sheet and Text entities. Sheet entity can have two Text's: privacyNotes and termsOfUse.
Both of Text type. So in XCode data modeler I create to-one relationships called "privacyNotes" and "termsOfUse" in Sheet with Text destination. Next goes to-one relationship "sheet" in Text. Then I select that Text.sheet relationship as inverse for Sheet.privacyNotes. So far so good. But when I set same Text.sheet relationship as inverse for Sheet.termOfUse XCode deletes this relationship as inverse Sheet.privacyNotes!
I understand that relationships in DB can be not so simple compared to Objective-C objects relationships, but I really don't get why SQLite or (CoreData) can't reuse one relationship as inverse for FEW other relationships?
A little peek under the abstraction hood might be enlightening*: a relation can only be the inverse for exactly one other relation because, in the backing store, they're represented by the same data. If a Text and a Sheet can have a certain relationship, Core Data does what a good human data modeler would do and stores that relationship as succinctly as possible. The relation properties of the entity objects are just ways of looking at that relationship.
To get the effect of what you're going for: go ahead and give Sheet properties for privacyNote and termsOfUse; but give Text properties like sheetIAmTermsFor and sheetIAmPrivacyNoteFor, and set them as inverses appropriately. Then in the Text class, add a synthetic property along these lines:
// in interface
#property (nonatomic, readonly) Sheet *sheet;
// in impl
-(Sheet *)sheet
{
if ([self sheetIAmTermsFor])
return [self sheetIAmTermsFor];
else
return [self sheetIAmPrivacyNoteFor];
}
If you want to write a setter too, you'll have to decide which role that setter should bestow on the Text (which Core Data can't figure out for you, another reason a property can't be the inverse of two different properties.)
If you need to enforce a constraint that a Text can only ever be a "privacyNote" or a "terms" but never both, override the setters for sheetIAmTermsFor and sheetIAmPrivacyNoteFor, following Apple's pattern in the docs, and have each null the other property when set.
(* Apple regards the SQLite databases Core Data generates as private to their implementation, but inspecting their schemas can be very educational. Just don't be tempted to write shipping code that goes behind CD's back to poke at the db directly.)
You are far better off having a one to many relationship between Sheet and Text with a validation limit of 2. Then you should have a type property in the text which declares it as either a privacyNotes or termsOfUse. From there you can add convenience methods to your Sheet subclass that allows you to retrieve either one.

Getting Core Data Entity from a Parent Entity

I'm trying to retrieve data from an Entity in Core Data where I know the value of a related Entity.
IE:
Entity1
-attrib1.1
-attrib1.2
-relationship1
Entity2
-attrib2.1
-relationship1
Entity1 has a to-many relationship to Entity2 on relationship1.
I'm trying to get the value of Entity2 where Entity1.attrib1.1 = XXX.
I tried using NSPredicate, but I'm not sure how, if possible, to write the syntax in the predicateWithFormat method.
If this doesn't make sense, sorry. I'll try to clear up if needed.
I have searched google and here, but haven't found anything. Maybe my eyes are giving out? ;)
I think you're trying find instances of Entity2 where Entity1.attrib1.1==XXX and Entity1.relationship1 contains a reference to the Entity2 instance. From your description, it's not clear if Entity2.relationship1 is the inverse of Entity1.relationship1. If not, you really should create the inverse relationship and set it as such in the data modeler. Unless you really know what you're doing and are sure you do not need the inverse relationship, Core Data will not work as you expect unless the inverse relationship exists.
Once you have the inverse relationship from Entity2 to Entity1 (let's call it inverseRelationship for sake of example), you can perform a fetch request on Entity2 using an NSPredicate instance with the format string
inverseRelationship.attrib1.1 == XXX
if the inverse is a to-one relationship or
ANY inverseRelationship.attrib1.1 == XXX
if the inverse is also a to-many relationship.

Core Data - Relationship to dissimilar entities

Suppose I have the following data model:
Entity Person
Attribute name String
Attribute personType String
Attribute dailyRecords
Entity CarpenterDailyRecord
Attribute numberOfNailsHammered Int
Attribute picNameOfFinishedCabinet String
Entity WindowWasherDailyRecord
Attribute nameOfBuildingWashed String
Attribute numberOfWindowsWashed Int
I would like to establish a to-many relationship between the Person.dailyRecords and 1 of the daily record entities (which changes depending on the person type). Of course, i could create a CarpenterPerson and WindowWasher entity which each points to it's unique daily record structure, but i have to group people together in my app somehow.
so if i do a Group Entity:
Entity Group
Attribute people array
i'm still stuck. how do i point to multiple & different Person entities?
There must be an obvious answer, it's just i'm so new to all of this. thanks!
Create a parent (DailyRecord) entity that handles the relationship (Person <-->> DailyRecord). [CarpenterDailyRecord|WindowWasherDailyRecord] then inherits from DailyRecord.
The risk with this, however, is that all of the children (WindowWasherDailyRecord, CarpenterDailyRecord) will be in one table in the underlying sqlite structure and therefore can cause a performance impact. This is not a reason to avoid inheritance, just something to be aware of while designing your data model.

Resources