How to work with Core Data relationships? - objective-c

I have two entities:
Patient
- firstName
- lastName
- scheduledAppointments <---->> Appointment
Appointment
- date
- times
- scheduledPatient <<----> Patient
Basically I have one Patient with many appointments. How do I set the scheduledPatient in the Appointments entity? I've tried this so far:
[self.appointment setScheduledPatient:[self.patientArray objectAtIndex:indexPath.row]];
self.appointment.scheduledPatient = [self.patientArray objectAtIndex:indexPath.row];
They work when I'm editing an appointment. But it returns a SIGBRT when I'm adding a new appointment.

Your code seems to be correct.
Therefore I suppose that most likely you have not defined the inverse relation properly in the .xcdatamodel file.
For what I understand you have a one-to-many relationships. That is, one Patient may have a number of Appointments. Therefore, an appointment belongs to one patient. In order for this relation to be semantically correct, you need to let it know how they relate to each other. In order to do so you need to specify what is the inverse element of each of the elements in the relation.
In the picture below you can see how a Region may have a number of states, and a state belongs uniquely to a region. Notice the arrow connecting the elements of the relation, how the "many" has a double arrow and the "one" has a single arrow.
I believe that you most likely forgot to specify this in the xcdatamodel file.
Check out this link for more information:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html
Inverse Relationships
Most relationships are inherently bi-directional. If a Department has a to-many relationship to the Employees that work in a Department, there is an inverse relationship from an Employee to the Department. The major exception is a fetched property, which represents a weak one-way relationship—there is no relationship from the destination to the source (see “Fetched Properties”).
You should typically model relationships in both directions, and specify the inverse relationships appropriately. Core Data uses this information to ensure the consistency of the object graph if a change is made (see “Manipulating Relationships and Object Graph Integrity”). For a discussion of some of the reasons why you might not want to model a relationship in both directions, and some of the problems that might arise if you don’t, see “Unidirectional Relationships.”

Related

Core Data ordered many-to-many relationships

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.

iOS CoreData - Rebuild relationships

I'm wondering if it's possible to "rebuild" relationships in Core Data.
Basically, I messed up when creating my entities, getting data from a SQL server i filled my entities as tables (one table by one table) and it seems now that the relationships are not working.
Let's take an example :
I've set up my model with my two entities (department and employee), with a relation one-to-many "myRelationWithDepartment" (one department many employees), and generated the managed object subclasses accordingly.
I got table department and table employees from my SQL server and inserted all employees in my entity employee and only then (because i have to retrieve first employees) all departments in my entity department, using Core Data, saving context, etc. Everything is fine, just the relationship is not working.
Now I'm able to make a fetch request upon a department or an employee, it works fine. But if I retrieve an employee and do this :
[[anEmployee myRelationWithDepartment] departmentName];
it's returning nil, no compilation warnings or errors, it just seems that no department is linked to an employee.
So I assume that the relations are not working.
I've included in the model the "id"s I had in my SQL tables, so I'm able to link them manually (but i have multiple entities actually).
I've gone through the Core-Data guide and found this :
[aDepartment.employees addObject:newEmployee]; // do not do this!
then KVO change notifications are not emitted and the inverse relationship is not updated correctly.
Recall that the dot simply invokes the accessor method, so for the same reasons:
[[aDepartment employees] addObject:newEmployee]; // do not do this, either!
That's why I assume relationships are badly shaped. Is there a way to rebuild the relationships afterwards (since i share some id's in the model between entities)?
I dig up more in Apple's documentation and relationship has to be filled manually :
To create the relationship "link" :
anEmployee.myRelationWithDepartment = departmentObject;
Alternatively, you can use:
[department addEmployeeObject:anEmployee];
Then when fetching objects you can access properties of related entities.
The problem is that Core-Data is "sold" as everything is doing quite by itself and in reality it's much deeper as it seems at first glance.

Setting up a "to-many" relationship value dependency for a transient Core Data attribute

I've got a relatively complicated Core Data relationship structure and I'm trying to figure out how to set up value dependencies (or observations) across various to-many relationships. Let me start out with some basic info. I've got a classroom with students, assignments, and grades (students X assignments). For simplicity's sake, we don't really have to focus much on the assignments yet.
StudentObj <--->> ScoreObj <<---> AssignmentObj
Each ScoreObj has a to-one relation with the StudentObj and the AssignmentObj.
ScoreObj has real attributes for the numerical grade, the turnInDate, and notes.
AssignmentObj.scores is the set of Score objects for that assignment (N = all students).
AssignmentObj has real attributes for name, dueDate, curveFunction, gradeWeight, and maxPoints.
StudentObj.scores is the set of Score objects for that student (N = all assignments).
StudentObj also has real attributes like name, studentID, email, etc.
StudentObj has a transient (calculated, not stored) attribute called gradeTotal.
This last item, gradeTotal, is the real pickle. it calculates the student's overall semester grade using the scores (ScoreObj) from all their assignments, their associated assignment gradeWeights, curves, and maxPoints, and various other things.
This gradeTotal value is displayed in a table column, along with all the students and their individual assignment grades. Determining the value of gradeTotal is a relatively expensive operation, particularly with a large class, therefore I want to run it only when necessary. For simplicity's sake, I'm not storing that gradeTotal value in the core data model. I don't mind caching it somewhere, but I'm having a bitch of a time determining where and how to best update that cache.
I need to run that calculation for each student whenever any value changes that affects their gradeTotal. If this were a simple to-one relationship, I know I could use something like keyPathsForValuesAffectingGradeTotal ... but it's more like a many-to-one-to-many relationship. Does anyone know of an elegant (and KVC correct) solution? I guess I could tear through all those score and assignment objects and tell them to register their students as observers. But this seems like a blunt force approach.
I just postet a project on github which probably solves part of the problem with observings
http://github.com/mbrugger/CoreDataDependentProperties
A more detailed description of the project can be found there.
-(NSArray*) keyPathsForValuesAffecting would not have solved your problem as this only works across to-one relations
In addition you should not make the dependent attribute transient, as it makes your context "dirty" (unsaved changes) already after recalculating all values after loading

How would you model a "default child" flag with an ORM?

I'm using an ORM (SQLAlchemy, but my question is quite implementation-agnostic) to model a many-to-many relationship between a parent class and its children.. I was wondering, what would be a simple way to express the concept "one of the children is the default/main one"?
For example, I'd need to persist the following:
This Person instance has Address X and Y, the main one is Y.
I saw this implemented using a "middle" class like "PersonAddressRelation" that would contain "Person", "Address" and the "main" flag, but I think it looks a bit cumbersome.. Is there a better way?
The simplest way would be to have a join table, PersonAddressRelation, and also a DefaultAddress column on the Person table that keys to the Address table.
A couple of remarks.
M:N relationships don't specify 'parent' and 'child', as there's no parent nor a child: there are simply two entities having an m:n relationship via a 3rd entity (the intermediate entity).
'Address' is in general not a valid entity type, as semantically it has no identity, similar to a 'name' has no identity (first name, last name). You'll see this when you look at re-using an entity instance of type Address: you won't do that in general. (though you will re-use a Customer entity instance for example, when the customer has multiple orders)
You want to specify an attribute on the M:N relationship (default), as it belongs there. This means that the relationship itself forms an entity (which is the intermediate entity, often it has just two FK fields forming the PK). This is called an 'objectified relationship', as the relationship itself is seen as an entity. Other examples of this are Employee m:n Department and you want to specify the StartDate an employee started for a department the employee works for.
So in general: create the intermediate entity, as it in general should be there, and add the attribute there. In this particular case with Address, be really sure you are re-using Address instances among related entities (Person). If not, merge Address with Person OR if a person can have multiple addresses, create a simple 1:n relationship between Person - Address, to normalize it out, though don't be afraid to merge address data into the entity it is related to, as often address data is really not re-used (so your m:n relationship is really not there: there's no Address instance which is related to multiple person instances.

Association end is not mapped in ADO entity framework

I am just starting out with ADO.net Entity Framework I have mapped two tables together and receive the following error:
Error 1 Error 11010: Association End 'OperatorAccess' is not mapped. E:\Visual Studio\projects\Brandi II\Brandi II\Hospitals.edmx 390 11 Brandi II
Not sure what it is I am doing wrong.
I believe I can add some more clarity to the issue (learning as I go):
When I look at the Mapping details and look at the association, the column for operatoraccess table (from above) is blank and the drop down only includes field from the linked table.
The Entity Framework designer is terrible - I've had the same problem many times (and your problem too, Craig):
This happens when you have a many-to-one association which is improperly setup. They could very easily fix the designer to make this process simple; but instead, we have to put up with this crap.
To fix:
Click on the association, and go to the mapping details view.
Under association, click on Maps to <tablename>. Choose the table(s) which make up the many side of the relationship (ie. the table(s) which make up the *-side of the association in the designer)
Under Column, choose the table-columns which map to each entity-side Property. You get this error when one of those entries are blank.
I had the exact same problem and this is what I did to fix it.
Make sure you have an Entity Key set in your designer on the tables your making an association with. Also check that StoreGeneratedPattern is set to Identity for that Entity Key.
There's not a lot of information in your question, but, generally speaking, this means that there is an incompletely defined association. It could be that you have tried to map one table with a foreign key to another table, but have not mapped that other table. You can also get this error when you try to do table per type inheritance without carefully following the steps for implementing that feature.
Not sure of the answer, but I've just posted a similar question, which may at least help clarify the issue you are experiencing.
Defining an Entity Framework 1:1 association
I had to go back into the database itself and clarify the foreign key relationship
I had this problem in the case where I was creating both many to 0..1 and 0..1 to 0..1 associations. One entity needed associations to multiple tables, and that entity did not have foreign keys defined for those tables.
I had to do the table mappings step that is given in the accepted answer, but note that it wasn't only for many to many associations; it applied to all the types of associations I added for this entity.
In the Mapping Details view, I had to select the entity with the non-foreign key ID columns to the various tables. This is not always the "many" side of the relationship. Only there was I able to map the related entity property to the appropriate property in the original entity. Selecting the "destination" entity would not allow me to select the properties that I needed to, and the error would still exist.
So in short, I had to map using the table related to the entity that had the "non-foreign key" ID fields corresponding to the various entities' (and their tables') primary keys that I needed to associate.
Entity A
various other properties...
Id
ContactId
OrderId
etc.
Contact entity
Id
FirstName
LastName
etc.
In the mapping details, I selected Entity A's table. It then showed both ends of the association. I mapped its Entity A's Id property to its table's actual ID column (they had different names). I then mapped the Contact entity's Id field to the ContactId field on the A entity.
Simply select the many relationship table (*) from the Association>Edit Mapping & select the appropriate relationship