Relationships in Core Data just confuse me. I've read and read, but I just don't get it. I guess it doesn't help that I'm usually frustrated when reading. I want to do something really simple:
I have an Entity called Pictures and an Entity called User. I want Users to be able to like and tag other people in pictures, so each Picture entity has two relationships:
Picture Entity:
UsersWhoLikedThePicture (to-many):
Destination: User
Inverse: Picture
UsersWhoAreTaggedInThePicture (to-many):
Destination: User
Inverse: Picture
But this is causing so much mix up in use, that I can't even begin to describe. It's inconsistent. Someone likes a picture causes them to be removed as a tagged user, and like one picture causes your likes from all other pictures to be removed. Ahhh it's such a mess..does my structure look ok? How would I model this?
In addition to Matthias Bauch answer, I could give you some hints to understand relationships.
First, when you deal with Core Data you have to think in term of objects. By means of this astraction you could think at your model as a graph where nodes are the entities that you created in the model, while relationships are the links among those entities.
Now, about relationships, they could be of different types: one-to-one, one-to-many and many-to-many. Based on the type of relationships you have, you can create different link in the objects graph. For example, if a User has a to-many relationship with Picture, it means that each instance of object (of type NSManagedObject) has a link to different Pictures. User works as the source, Pictures, as the destination.
Inverse relationships are used by Core Data to maintain the graph consistency. In particular, they are useful when you deal with delete rules.
Each relationship has a delete rule associated with it. Cascade means that if you delete an object, say the User, Core Data will delete the object (the Pictures) linked to it for you. Deny doesn't allow to delete an User if there are Pictures linked to it. Nullify means the link from a Picture to a User will be broken. It doesn't mean that the objects are deleted. In terms of object graph, it means that you haven't anymore a link between those objects. No Action means that the source is deleted, the destination is always there and it continues to point to an object that doesn't exist anymore. So, unlike Nullify, you need to broke that link manually. If not you could have a graph inconsistency. Try to avoid this type of relationship.
If you want to know something else, let me know.
EDIT
Take a look at Core Data Programming Guide Relationships section for further info.
I don't know if this is even possible, but it sounds like you used the same inverse target for two relationships. Don't do that.
The right way would be something like this:
Related
In the Parse.com API reference for Swift on iOS, it is very clear when to use the different kinds of One-to-Many relationships, based on the expected size of the Many side.
But I find it less clear on what kind of Many-to-Many relationships to use when both sides could be very large.
In my case, I have a Charity object that my Users can make small (often one-dollar) contributions to--so each User could conceivably make thousands of these contributions, and each Charity could have thousands of Users making contributions to it.
The Many-to-Many options listed for this kind of thing are Parse Relations, Join Tables, and Arrays, of which the docs explain:
Arrays should be used when the relationship will reliably include under 100 references, which is very clear and helpful guidance that I should not use Arrays.
The docs say Parse Relations could be used, for instance, to connect Books with multiple Authors and Authors with multiple Books--a situation in which a given Book is unlikely to have over 100 Authors, and only rarely will an Author have over 100 Books--so it's unclear if this is appropriate when both sides could be very large, as in my case.
The docs say Join Tables should be used when extra metadata should be attached to each relationship, so for one thing, I don't at present have an explicit need for this, and for another, the docs don't seem to even mention anything about how or if it matters how large each side of the Many-to-Many relationship is.
In the absence of any other information, it looks like I should use Join Tables, but only because the docs don't imply that I shouldn't, and not for the reason the docs say I should.
Which seems like a flimsy rationale.
I would greatly appreciate any guidance anyone can give.
Behind the scenes, when you use Relation, Parse Server automatically creates a Joint Table for you and delivers some APIs for easily managing and fetching its data. So, in terms of performance, it should be very similar.
The downside of the Relation is the impossibility to add new fields to this "Joint Table" it creates. So, if you need, for example, to store the charities that each of the users like, a relation between User and Charity would be a good fit, because you just need to store that the relation exists and do not need to store any extra information.
On the other hand, if you need to store the donations that each user did to each of the charities, I'd create a Joint Table called Donation or UserCharity with a pointer to the User class, a pointer to the Charity class, and the value of the donation. In this case, Relation is not a fit because you need to store the donation value.
I've read through a bunch of tutorials to the best of my ability, but I'm still stumped on how to handle my current application. I just can't quite grasp it.
My application is simply a read-only directory that lists employees by their company, department, or sorted in alphabetical order.
I am pulling down JSON data in the form of:
Employee
Company name
Department name
First name
Last name
Job title
Phone number
Company
Company name
Department
Company name
Department name
As you can see, the information here is pretty redundant. I do not have control over the API and it will remain structured this way. I should also add that not every employee has a department, and not every company has departments.
I need to store this data, so that it persists. I have chosen Core Data to do this (which I'm assuming was the right move), but I do not know how to structure the model in this instance. I should add that I'm very new to databases.
This leads me to some questions:
Every example I've seen online uses relationships so that the information can be updated appropriately upon deletion of an object - this will not be the case here since this is read-only. Do I even need relationships for this case then? These 3 sets of objects are obviously related, so I am just assuming that I should structure it this way. If it is still advised to create relationships, then what do I gain out of creating those relationships in a read-only application? (For instance, does it make searching my data easier and cleaner? etc.)
The tutorials I've looked at don't seem to have all of this redundant data. As you can see, "company name" appears as a property in each set of objects. If it would be advised that I create relationships amongst my entities (which are Employee, Company, Department), can someone show me how this should look so that I may get an idea of what to do? (This is of course assuming that I should use relationships in my model.)
And I would imagine that this would be the set of rules:
Each company has many or no departments
Each department has 1 or many employees
Each employee has 1 company and 1 (or no) department
Please let me know if I'm on the right track here. If you need clarification, I will try my best.
Yes, use relationships. Make them bi-directional.
The redundant information in your feed doesn't matter, ignore it. If you received partial data it could be used to build the relationships, but you don't need to use it.
You say this data comes from an API, so it isn't read-only as far as the app is concerned. Worry more about how you're going to use the data in the app than how it comes from the server when designing your data model.
I am designing an app which tracks data on Game objects. Each Game has a name, a date and other attributes. The problem I am having arises because I want the user to be able to add more names (for example) to pick from in the application. (in this case from a UITableView). So the user is presented with a list of names to choose from, and if the one they want is not in the list, they can add one to the list.
My solution is that I currently have a second entity called GameName so that I can show the user a list of those game names to pick from when they are adding a new Game. I just call an NSFetchRequest on all the GameName objects and display them in the UITableView. There doesn't have to be a Game object created yet to do this.
My dilemma is that I want to know if this is a good practice. It seems that if I do it this way, I will end up having a lot of entities with just one attribute, for the sake of allowing the user to pick from and add to a customizable list.
I hope this makes sense. I can clarify anything upon request.
Your approach is fine, and is commonly used in database design. The entity you want to add is called a "domain table" in databases. See this page, in particular this paragraph:
In a normalized data model, the reference domain is typically specified in a reference table. Following the previous example, a Gender reference table would have exactly two records, one per allowed value—excluding NULL. Reference tables are formally related to other tables in a database by the use of foreign keys.
Of course, you probably want to have an optional relationship between the GameName and Game entities.
I have a couple of Core Data entities... Student and Exam.
Now, the Exams is initially just one object per exam - Maths Exam 3, English Exam 2 etc.
There is a relationship between Students and Exams in my data model (a student can have several exams). But initially, the Exams are just floating free, and not attached to any students.
How would I make a copy of one of the exams and attach it to a student?
If I do something like:
[student addExamsObject:examObject];
...then I think it simply references the original exam to the student, rather than making a copy.
I need a copy because the Exam has a boolean 'hasTaken', which is YES when the student has taken the exam. But if I set that now, it will make it seem like all the students with that exam have taken it.
Clarification: I would rather not restructure my model. The data is taken from a couple of xml files, one each for Students and Exams, which are parsed into the Core Data store. For instance, an Exam object might look like this:
name:Maths 5
class-id:12
year-id:4
student-id:0
..with a Student object looking like
name: Dave
class-id:12
year=id:4
student-id:222
Various rules are meant to guide which exams get attached to which students... for instance if all the Exam's ids are 0 then all students take the exam. If class-id and year-id match, and student-id is 0, then the Exam gets added to students with the same class and year. If the student-ids match, then just that student takes the Exam. etc etc.
I cannot change the way the xml is outputted from the server.
Another issue is that Exam has too-many relationship to a Question entity... in other words, the questions in the Exam. And I have to store answers to the questions that each student gives in an exam.
Edit: I wish people would try to answer my question rather than tell me to restructure my whole program. There are reasons why the data model has been structured like it is.
Edit2: Maybe I will have restructure....
Exam shouldn't have a hasTaken property. Think about it in the real world. An Exam would not know about who has taken it because many people could have taken it. The instance of taking an exam, then, should be a first-class concept in your model.
Consider this:
Exam has many TakenExams, TakenExams belongs to Student http://yuml.me/6627495d
Now the concept of taking an exam is a real object, you can then model assocation metadata as well, such as dateTaken, score, and so on.
Also remember that Core Data expects you to have all of your inverse associations set up as well.
You don't usually copy an entity. (I'm not sure what happens if you call copy on an NSManagedObject... it's not explained in the documentation, as far as I know. Experts can correct me. )
Just create another entity, or write a method which does just that.
I think another way is to make many-to-many relationships between Exam and Student:
create relationships in Exam called studentsToTakeThisExam and studentsWhoTookThisExam.
create relationships in Student called examsToTake and examsAlreadyTaken.
and set up the inverse relationships accordingly.
I would not argue (as You requested) if your modeling is correct or not. The procedure to copy an entity is, in general, quite complex, owing to the fact that, besides attributes, you also need to deal with the entity's relationships and copy them. I can not post here a huge amount of source code showing how to accomplish this, however, I can point you to a book where this issue is described in detail, with all of the source code you need. The book is the one from Marcus Zarra, "Core Data Apple’s API for Persisting Data on Mac OS X" by "The Pragmatic Programmers".
You really don't want to copy an Exam in this situation. You'd end up with lots of identically named Exams which didn't have a relationship with each other, and then you'd be forced to group them together (if you wanted to) by their name.
I'd recommend a new entity (perhaps "ExamSitting"?) which represents a Student sitting an Exam. You could then a to-many from Student to ExamSitting, and a to-many from Exam to ExamSitting. This enables you to have as many attributes on the ExamSitting as you like then (hasTaken, grade and so on).
Edit
Okay, given your clarification, I have a point or two to add (although they may not be what you're looking for). I understand that you're loading from files with a particular structure, but that doesn't necessarily have to dictate your structure.
With the XML files laid out as you now describe, I would still use an Exam - Student - ExamSitting model. If I were to implement it, I'd load all the Students, and then, for each record in the Exams file, I'd create one Exam object, and then a number of ExamSitting objects, one for each Student that fits the criteria defined in the record. As I mention above, this enables you to store more information about each event, such as mark, takenDate and so on.
If you're sure there's no requirement to be able to store additional information at this granularity, you could just create a to-many relationship studentsTakingExam. This could be populated as you load each exam record by querying the loaded Student entities.
I'm working on my first app using Core Data and I need to assign a type (with an associated name attribute) to a couple of entities.
Below is my object model so far.
The room and item types will be updated from time to time over the network.
Is this the best way to implement this using Core Data? Thanks :)
Edit: To try to explain better: for example, rooms may be Bedrooms, Kitchens etc. Items can be Aircon, Security Camera etc. The only difference between the different room and item types is the name text. The list of valid name texts will be updated so I don't want to hard code it in the app. Also, the user can create multiple rooms and items of the same type, which is why they are numbered (roomNumber,itemNumber)
improved Core Data Model Image http://img42.imageshack.us/img42/8458/picture6c.png
Nick, try and avoid the temptation of thinking of Core Data as a database. Design your model from the point of view looking at using the objects in your code.
i.e. your relationship properties are collections (or singluars) of the related thing.. you should rename the relationship JobLocation.JobLocationToRoom as just JobLocation.rooms
And yes, using Core Data will be quite straight forward, but it's hard to give you a definitive answer with such a vague question.
Perhaps my question wasn't clear, but I found the answer in the Apple iPhoneCoreDataRecipes demo code
The relationship I wanted to model is similar to Recipe -> RecipeType.
In addition to the other answers, you don't need to model separate ID attributes. Core Data managed objects automatically have managed object IDs that are handled for you entirely behind-the-scenes by the framework.