CoreData Entity Unique Attributes - ios

I am building an app around CoreData and have bumped into a dilemma. Hopefully has a simple solution.
I have an entity, 'Equipment'. Each equipment object has a name and type. When selecting a type depending on the selection, I need to add more attributes to that entity, but only to that object.
So if I have an equipment object of type bowl. I want to add the attribute containsMilk for example. Whereas if the type is knife, I want to add the attribute isBreadKnife.
Any tips on how to do this? As you can see, not every equipment object will necessarily have the same attributes and different types require unique ones.
How can I achieve this? Thanks.

Related

Data model for enum with associated values

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.

Core Data Attributes

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.

Core Data Model

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.

How to store other NSManagedObjects as property of a NSManagedObject

I am new to iOS programming and I'm doing up a simple function of an iOS application. Currently, I've created an entity called Players, and I'd like the entity to have a property, in which it stores other NSManagedObject like an array.
This is because I want a player to be able to have friends in the game and this is the way I've thought of; I could just access a player's friend's list via
[playername friendList]
May I know if this is the way to do so? Because for an entity's attribute type, I couldn't use NSMutableArray or NSArray as its type. If it is, may I know how I can store it? If not, is there a better way to achieve that?
This is the purpose of relationships in the Core Data model. Add a relationship between the two entities (and an inverse) and add the managed objects to that relationship.
See this section of the Core Data guide.
You need to create a relationship between the models, which are represented with NSSet (or NSOrderedSet, by checking "ordered", if the order is important.)
Ordered Sets are similar to arrays, except all the objects are distinct (no duplicates).

CoreData -to many relationships

I'm beginning to use Core Data and I'm trying to get a solid understanding of how it would work in my case. I'm building an iPad photo album app that will allow users to filter their results based on keywords and a couple of other attributes associated with each photo. The attributes would be basic stuff like orientation and whether its color or not. Keywords will be based on a set of defined values that the user will have to choose from.
Here's a rough outline of what I have in the Core Data Model so far:
Entities (attributes):
Photos (id, title, desc, file path)
Keywords (id, name)
Since a photo can have multiple keywords associated with it, do I create a relationship from 'Photos' with a destination of 'Keywords' and make it a -to many relationship? Is that correct/crazy/completely wrong? How would I go about adding/fetching records for that relationship?
If the Keywords are defined and the user can choose them from a defined list, I wouldn't have used an entity Keyword. Tip always use singular names (Photo, Keyword). I would have the keywords in a plist and the user chooses a few, you could then create a comma separated string to save as a property on Photo. As Joseph mentioned, you want to subclass NSManagedObject and I would then add a method that receives a string (keyword) and returns a BOOL indicating if that keyword was part of the comma separated keyword values on the Photo property
This is correct. There are several approaches to accessing this, but the most straight-forward way is to generate NSManagedObject subclasses (Editor->Create NSManagedObject Subclass...). When populating these the Photo entity, the Keyword relationship will be populated in the property called keywords.

Resources