If I'm making an Entity in Core Data to handle possible values a person can select in a questionnaire form do I have to create an attribute for every possible selectable question? For example my Entity named Person has attributes for name, date, time, and than a bunch of possible answers to select radio-button style that should be added to the Person Entity. Is it better to use a separate Entity for the questionnaire portion.
Edit for better clarity:
The app/survey form is a list of questions with a radio button style check box. If the question applies to them they touch the circle button and it fills in the circle. So its a boolean value. However I'm just not sure if I have to make each one of those questions an boolean attribute or not? This seems like a simple enough project to start learning Core Data which is the purpose of using Core Data instead of some other modeling and persistence solution.
If your properties are y/n answers, that would be boolean attribute e.g.:
Person.licensed = y/n
If your properties have more than y/n possible answer you might use a number attribute:
Person.licensed = 1(y), 0(n), -1(Unknown), -2(Ineligible)
You may need more flexible properties. Maybe there are many types of licenses:
Person.licenses --> Related Entity License with attributes- license.type, license.issueDate, license.expireDate
Then, if you are doing something like a survey, there are many other potential paths. You'll need to elaborate on what you are doing for more help.
Separating the two entities is a good idea as it avoids confusion and keeps your code cleaner. When you step away from the project and return to it 4 months later, there will be no issues discerning where data is saved and from where to retrieve it.
Your Person entity will have its attributes (name, email, etc) and the Questionnaire entity will have its attributes- yes, one for each question with a Boolean type.
Based on your comment you don't need a Boolean or any other attribute. You have a set of questions, which are just instances in the data store. You could group them into a questionnaire if you want, which would be another entity and a relationship between them. Your person is another entity, and has a to-many relationship to question. As the user ticks questions that apply to them you add those questions to the relationship.
Related
I'm trying to figure out what's the recommended way to implement enum with associated values in Core Data data model. Let's say I have a book entity and I want to save in database how I got the book, like:
it's bought by me (or other family members)
it's borrowed from someone (e.g., a colleague)
it's given as a gift by someone (e.g., a friend)
This would be an enum in swift:
enum WhereItCameFrom {
case Bought(who: String, date: Date, where: String)
case Borrorwed(who: String, date: Date, dueDate: Date)
case GivenAsGift(who: String, date: Date, forWhat: String)
}
I'm thinking to implement it in data model using inheritance , as below:
Introduce a parent entity WhereItCameFrom and define the above cases as its children entities.
Define a to-one relationship from Book to WhereItCameFrom. Its deletion rule is Cascade.
Define a to-one relationship from WhereItCameFrom to Book. Its deletion rule is Deny.
See the diagram:
I'm wondering if this this the right way to do it and I have a few specific questions.
1) What's the typical way to implement enum with associated values?
I think my above modal is good. But just in case, are there other better ways to do it?
2) Is entity with no attributes normal?
In above diagram, WhereItCameFrom doesn't have any attributes. At first I added a type attribute to it to indicate if it's a Bought, Borrowed, or GivenAsGift entity. But then I realized this information is implicit in its child entity class type, so I removed it. So the only purpose of the parent entity is to hold the relationship. Is this use typical in Core Data?
3) Will the old object be removed automatically when modifying relationship at run time?
Suppose I modify book.whereItCameFrom relationship value at run time. Its previous value is a Borrowed object. Its new value is a GivenAsGift object. Do I need to delete the Borrowed object manually (I mean, doing that explicitly in application code)?
I guess I should do it. But given Core Data is a framework helping to maintain data consistency in object graph, that seems awkward to me. I wonder if Core Data has some feature that can figure out the Borrowed object is not needed and delete it automatically?
Thanks for any help.
UPDATE:
In the third question, after the old Borrowed object is disconnected with Book object, is my understanding correct that, from the Borrowed object perspective, the peer object has been delete and hence the peer object's Cascade deletion rule is applied to the Borrowed object? If so, then it will be deleted automatically. I think the real question here is if deletion rule applies to relationship update or not. I'll do some experiments on this later today.
A few thoughts...
1) What's the typical way to implement enum with associated values?
I think my above modal is good. But just in case, are there other better ways to do it?
I can't comment on typical ways of implementing enums with associated values, but your model seems to make sense. One word of caution: if you search StackOverflow for questions regarding entity inheritance, you will find several answers advising against using it. The way CD implements subentities (at least for SQLite stores) is to add all the attributes of all the subentities to the parent entity SQLite table. That's handled for you "under the hood" by CoreData, but the SQLite table can potentially end up being very "wide", which can affect performance. I've never found it an issue, but you might want to have that in mind if you have lots of data and/or the entities are more complex than you indicate in the question. Subentities can also cause issues in some rare situations - for example, I've seen questions indicating problems with uniqueness constraints.
2) Is entity with no attributes normal?
It's unusual, but not a problem. However, as all three subentities have date and who attributes, it would be wise to move these from the subentities to the parent WhereItComeFrom entity. (Otherwise, as noted above, your parent entity table will have three columns for date (one for each subentity) and three for who).
3) Will the old object be removed automatically when modifying relationship at run time?
No. If you modify the book.whereItCameFrom relationship value at run time, with a GivenAsGift object replacing a Borrowed object, CD's graph management will ensure that the Borrowed object's book property is set to nil. The cascade rule does not prevent objects being "orphaned" in this way and you must manually delete the Borrowed object.
I'm making an iOS app with thousands of flash cards with questions. The questions pool has about 10,000 questions, and is divided in 5 categories. One single question can have only one category. Categories won't change, they are fixed. Questions are just text. No images involved.
I was thinking about two approaches:
1) Create an Entity for the question with a category field (int) in it.
Fetch the results to get only the questions of a specific category.
2) Create 5 Entities, all with the same fields, except for the category, which has a default value corresponding with the category.
Why option 2?
I think option 1) is the clean proper one, but the app has so many questions that I'm thinking that submitting a query filtering a specific field, is maybe slower than retrieving a completely different Entity. I'm thinking from an SQL point of view, where maybe performing a SELECT on one table and then another one, should be faster than a SELECT...WHERE on the same table?
I agree with you, option 1 is the clean proper one. Retrieving the category from another entity will add minimal overhead. Moreover, if you have to edit a category you have only one entry to change. You can also add other categories more easily.
If you are really concerned about performance (and I don't think you should at that point) you can code both and do a speed test. But that is really overkill and the difference will probably be insignificant.
I recently asked this question about how best to retrieve and display in a tableview the titles my FRC is using for section headers.
Following a line of research suggested by #Mike Pollard in the second answer to my question, I ran across this question and was immediately struck by the similarity to my situation, and by the 4th answer, posted by #aroth.
Aroth's approach certainly appears sound, and I've created a new Category entity. Specifically, Category has a to-many relationship with Item, and Item has a to-one relationship with Category. However I'm having trouble understanding one aspect implicit in his proposed solution, and, more fundamentally, in this relationship:
In my case, both Category(s) and Item(s)--"Item" is called "ListActivity" in my case, but "Item" will do for illustration purposes-- will be named via two corresponding user input fields, which seems like it could result in multiple entries of the same name in the Category list.
My question:
How can I ensure that when I fetch a list of Categories that I get a singular instance of each category, i.e., one category per row in the tableview, with no repeats? Will Core Data automatically assign each new incoming Item to a singular instance of the appropriate Category via the relationship? Or will it somehow test for and winnow the list down to one entry per Category name upon receiving the fetch request? Or must the filtering be done with a predicate in the fetch request?
Thanks!
Core Data will do what you tell it to. This sounds like an issue related to you creating content in your data store rather than an issue with the FRC and table view. It's your responsibility to search for and reuse existing objects rather than creating duplicates and adding them to the store - indeed, only you (your code) knows what constitutes a duplicate.
So, basically, as you create new items, use a fetch request and predicate to find the suitable existing category (or suggest categories based on partially entered names). Then, either connect to the existing category or create a new one.
I'm struggling with creating a suitable Core Data model for my app. I'm hoping someone here can provide some guidance.
I have two entities -- "Goals" and "Items". The Goals entity contains only a goal description, but any goal may have any number of subgoals, and these may extend multiple levels in a tree structure. Subgoals are to be contained within the same entity, so presumably the Goal entity will contain a pointer to "parent" which will be the parent goal of any subgoal.
There will also be an "Items" entity that contains a couple of text fields and a couple of binary items, and must be linked (ideally, by a unique identifier, perhaps objectID) to the particular goal or subgoal the item(s) are related to.
I am totally fumbling with how to set this model up. I know what attributes need to be in each entity, but the relationships, particularly between goals and "subgoals", has me stumped. I don't seem to be able to turn up any good examples of tree structures in Core Data on the Internet, and even the couple of books I have on Core Data don't seem to address it.
Can anyone here help an old SQL programmer get headed the right direction with these relationships in Core Data? Thanks.
Have you tried creating a one-to-many from Goal to itself, and a one-to-one from Goal to Item? The only thing I would worry about here is circular references.
Also, read Relationships and Fetched Properties in the CoreData Programming Guide.
Here is how it is done:
You set up a to-many relationship from Goal to Item in the model editor. Don't use any ids, foreign keys etc. This is old-fashioned database thinking - you can forget about it. Here we are only dealing with an object graph. The database layer is just an implementation detail for persisting the data.
Make two more relationships in entity Goal to itself: a to-one called parent, a to-many called subGoals. Make them the inverse of each other. Simple!
QED is correct, you can create a to many relationship on goal (call it subgoals) as well as a to-one relationship on goal (call it parentGoal) and set them as inverses to each other.
Then create another to many relationship (call it items) on the goal entity, with the inverse being a to one relationship on the item entity (call it goal). Then you're all set. You don't need to link items with a unique id, just add them to the items relationship.
Also note that if you did want to give items a unique id, do not use the objectID. The objectID should only be used as a temporary id as they are not guaranteed to remain the same. In fact they will change if you ever do a Core Data migration.
One way, though not really great, is to create a another entity, say subGoal, and each goal has one subGoal and each object of subGoal has many goal.
I have an entity (Order) that has a to-many relationship with an entity Item, which has a to-many relationship with an entity Note. If the price changes for a Note, or a Note is added, the 'price' attribute for the associated Order must update.
Right now, my solution is to have all Order objects sign up for NSManagedObjectContextDidChange notifications, and check all the inserted/changed objects to see if any of those objects is one of the Order's Item's Notes. However, this is very inefficient and hacky, and is leading to a few more performance issues that can be optimized away, but I'm starting to realize that my solution is what's faulty, not necessarily the issues.
So, what's the best way to do this?
EDIT: To answer the questions brought up by Rog: I'm looking to propagate the changes to model data, which are observed by view controllers via KVO. The problem I'm noticing is, if the price of a Note related to an Item is adjusted, there's no facility to account for this in Core Data. If I use keyPathsForAffectingPrice on Item, and return "notes", that only accounts for if notes are inserted/deleted, not if the Note price is adjusted.
If this wasn't Core Data, I'd write my own accessor for note price to just say [self.item willChangeValueForKey:#"price"], self.price = x, [self.item didChangeValueForKey:#"price"]; but that isn't possible since I can't do custom accessors in Core Data, right?
We problably need more details about your code to be able to help - i.e. are you looking at ways to propagate changes to your model data or to the UI?
Are you using a fetchedResultsController at the moment?
The way I see it, if your Order contains Items and the Items contain Notes, any updates to your "child" attributes will be effective immediately (provided you have your reverse relationships setup properly).
Then if you're looking at ways to updating your UI accordingly, then we need to know how you are currently fetching and populating your views with your Coredata entities.