NSFetchedResultsController update when relationship updates? - core-data

Imagine I have a data model that has 2 entities: Movie and Genre.
A Movie can belong to many Genres, as a Genre can have many Movies.
Now. I want to have a NSFetchedResultsController that observes the Genre entity (using the genre's name as a sectionNameKeyPath)
Say I import some data, and a Genre gets a Movie added to it during the import.
The question is: Will the NSFetchedResultsController delegate (controllerWillChangeContent: , etc.) methods be called (because the Genre.movies.count has changed)?
If not, how can I make that happen? In Swift?
(Yes I know there are other questions like this out there, but none seem to be succinct or have an official answer)
(May be related to this issue:)

Yes, it will update if the relationship on the entity updates. It will not update if a property in Movie changes even if the predicate is set to monitor that.

YES, on import of a Movie to a Genre, controllerWillChangeContent: of the FetchedResultsController observing Genre will be invoked.

Related

How to Add target NSManagedObject to another one with an inverse many-to-many Core Data relationship without duplicating target NSManagedObject?

I had encountered an issue one of my projects, I had spent dozen of hours to find the solution, I had made some progress, but still not getting what I would like to achieve ideally. I am still finding solutions myself now, while I would really appreciate anyone could share any insight for constructive solutions.
Issue:
How to add a target NSManagedObject from a master list as one object
of the references in another NSManagedObject with an inverse
many-to-many relationship between each NSManagedObject without
creating duplicate target NSManagedObject in the master list.
Note:
The following example used an analogy to the full data model graphs
to my real project. The analogy is what I can best describe the issue
I have, while the objects in the analogy do not fully share the same
name of the objects in the real project.
What I have now:
A master list of ingredient objects, which are unique among each
other.
A list of recipe objects, each of which would like to have different
ingredient objects to define the recipe object.
What do I want to achieve:
Ingredient objects can be inserted as multiple times into a single recipe object with each insert as unique count instead of making same ingredient being considered as one single count.
I did not want to duplicate each ingredient object inside of the
master list to be able to add multiple ingredients objects to each
recipe object or cross multiple recipe objects.
What I had tried:
Use Core Data to manage the ingredient and recipe as 2
NSManagedObjects.
Had created a relationship attributes called “allHostRecipes” on the ingredient managed object, and set it as “to-Many“ relationship to the recipe managed object
Had created a relationship attributes called “allUsedIngredients” on the recipe managed object, and set it as “to-Many“ relationship to the ingredient managed object.
These two relationships are set as “inverse”.
I had a Recipe Description View with a Table View that lists all the ingredients that are and will be included inside of the recipe.
I created another Ingredients Selection Table View that can be triggered in the recipe description view to pick each ingredient,which is going to be added into the recipe.
Each time when an ingredient is picked in the Ingredients Selection Table View, I call objectAtIndexPath(_:) on the NSFetchedResultsController that is for ingredients Table View from the ingredients’ master list to find the selected ingredient objects in its ManagedObjectContext.
Then I passed the selected ingredient managed object (SelectedIngredientManagedObject) back to Recipe Description View and called mutableSetValueForKey("allUsedIngredients").addObject(SelectedIngredientManagedObject) on the NSFetchedResultsController that is for fetching ingredients that is contained inside of a recipe object.
The “NSFetchedResultsController that is for ingredients Table View from the ingredients’ master list” and “NSFetchedResultsController that is for fetching ingredients that are contained inside of a recipe object” are separate instance variables in “Table Views of Recipe Description View” and “Ingredients Selection Table View”. But they referenced the same ManagedObjectContext.
What I had got now:
The selected ingredient managed object can be added to the recipe.
But, if I selected the same ingredient multiple times, it only get count once in the Table Views of Recipe Description View instead of showing multiple counts by each inserting, which is NOT what I want to achieve as described above.
My Question:
What should I do or adjust to achieve the functionalities that I had
to describe above?
What I think the directions to solve the issue:
What other things should I do when defining the “Many-to-Many”
relationship in Core Data model?
Does the fact that the “to-Many“ reference is using an NSSet cause the count issue?
Is it necessary to create multiple ManagedObjectContext to achieve the desired functionalities?
Should I clone the selected ingredient managed object as a new ingredient managed object? Which I had tried, and it will add duplicated ingredient to the ingredients’ master list. This is also NOT what I want. If I need to clone it, how can I make it right?
I really appreciate your time to view it, I am looking forward to having your insights. Thank you very much.
Regards,
Knight
You need to remodel the data slightly: Remove the many-many relationship from Recipe to Ingredient, and replace it with an intermediate entity (finding a good name is difficult, let's say RecipeIngredientDetails).
Create a one-many relationship from Recipe to RecipeIngredientDetails, say allUsedIngredientDetails, with inverse (to-one) recipe.
Likewise create a one-many relationship from Ingredient to RecipeIngredientDetails, say allHostRecipeDetails, with inverse (to-one) ingredient.
This addresses the problem with a direct many-many relationship, where each Recipe can be related to each Ingredient only once. (You are correct, this is in part a consequence of the relationships being modelled as Sets, which cannot have duplicate members). You have two options: you could just add multiple RecipeIngredientDetails objects, each related to the same Recipe and Ingredient pair. Each such object might represent a standard base quantity of the ingredient. Note that you could not have just one object for each Recipe/Ingredient pair, and try to add that object to the same Recipe multiple times: a given Recipe and a given RecipeIngredientDetails object can be related at most once.
But it might be better to add an attribute to the RecipeIngredientDetails, say quantity. You then only need a single such object for each Recipe/Ingredient pair, and can update the quantity attribute to reflect the amount of the ingredient that is appropriate for that recipe.
This is the approach mentioned in the CoreData Programming Guide section on Modeling a Relationship Based on Its Semantics:
For this sort of relationship, use an intermediate (join) entity. An advantage of the intermediate entity is that you can also use it to add more information to the relationship.
It is equivalent to adding a join table with foreign keys and additional columns to a SQL database. I'm not aware of any simpler way of achieving your objectives in CoreData - there is no way to directly add attributes to relationships.
Regarding the ordering issue that you mention in comments, you had added "a Double type attribute in the Entity to keep track of the order". If you have only two entities, and a many-many relationship, and you add the order attribute to the Ingredient then (for example) if "Flour" is the first ingredient for "Bread", it would have to be the first item for every other Recipe it is used in. In the approach I describe, you would add the attribute to the intermediate entity, RecipeIngredientDetails: the index (just as for the quantity) depends on both the recipe and the ingredient.
For indexes there is, however, another option I should mention: you could (in the data model editor) define the relationship from Recipe to RecipeIngredientDetails as ordered. The resulting property will be an ordered set (so you can insert, remove or move items to achieve the correct order).

Custom Class Object as an Attribute in Core Data? - Swift [duplicate]

I have 2 entities.
entity 1 - People
entity 2 - books
People entity has a property which is an array of string names of their favorite books.
I need to create a relationship that somehow maps the favorite book of a person to the corresponding book entity object(s).
I am not sure how to do this.
So far I have started by creating a relationship in core data model for people by setting destination to "books" and then for the books entity creating a relationship by setting destination to "people".
I don't see or understand how this will automatically pick out each of the person's favorite books...at the end of the day they are both seperate objects. How will the people class know that for a specific people instance that this, this and this book are that person's favorite?
Person attribute as array of string names of books -- very bad idea!
You need a to-many relationship with the Book entity. That's it.
Person <------------>> Book
Then, to get an array of book titles for a particular person:
(person.books as! Set<Book>).map { $0.title }
The person can have an additional to-one relationship (e.g. called favoriteBook) to one of the books.

NSPredicate for items in two-levels deep to-many relationship, w/o direct relationship

I'm trying to build a single NSFetchRequest predicate for the following (simplified) model:
There is a simple to-many relationship between a Category and a number of Brands.
Each Brand then has a modelNumbersData property which is binary data, a serialisation of an array of NSString modelNumbers which are exposed in a transient property on the Brand objects.
There is no direct relationship between Brands and Models. The relationship is that a Model's modelNumber may be in a Brand's modelNumbers transient property.
I would like to build an NSPredicate query to fetch all of the Model objects under a particular Category.
Fetching the Models for a Brand is easy, I can do "modelNumber IN $FETCH_SOURCE.modelNumbers". How do I now extend this query to originate with the category? It seems I need a SUBQUERY?
Furthermore, I am doing an NSFetchRequest, so unless I'm mistaken I need to start with "SELF.modelNumber IN (...)", so that we select from all Models.
Thanks in advance!
Ok, I got there first. For reference, the following works:
SUBQUERY(%#.brands, $brand, $brand.modelNumbers CONTAINS $modelNumber).#count > 0
I think the problem I was mostly having was neglecting the .#count component. Still don't quite understand this, but it seems to be necessary with all SUBQUERY statements.

Core Data Inheritance and Relationships

I´m a little confused about inheritance and relationships in core data, and I was hopping someone could drive to the right path. In my app i have created 3 entities, and none of them have (and are not suppose to have) common properties, but there´s gonna be a save and a load button for all the work that the user does. From my understanding I need to "wrap" all the entities "work" into an object which will be used to save and load, and my question is, do I need to create relationships between the entities? Because I have to relate them somehow and this is what make sense to me. Is my logic correct?
I'm implementing a budget calculator, and for the purpose of everyone understand what my issue is, I´m going to give an practical example and please correct me if my logic is incorrect:
Let´s just say you are a fruit seller, and because of that it´s normal to have a database of clients and also a fruit database with the kinds of fruit you sell. From my understanding I find two entities here:
Client with properties named: name, address, phone, email, etc.
Stock with properties named: name, weight, stock, cost, supplier, etc.
TheBudget with properties named: name, amount, type, cost, delivery, etc.
I didn´t put all the properties because I think you get the point. I mean as you can see, there´s only two properties I could inherit; the rest is different. So, if I was doing a budget for a client, I can have as many clients I want and also the amount of stock, but what about the actual budget?
I´m sorry if my explanation was not very clear, but if it was..what kind of relationships should I be creating? I think Client and TheBudget have a connection. What do you advise me?
That's not entirely correct, but some parts are on the right track. I've broken your question down into three parts: relationships, inheritance and the Managed Object Context to hopefully help you understand each part separately:
Relationships
Relationships are usually used to indicate that one entity can 'belong' to another (i.e. an employee can belong to a company). You can setup multiple one-to-many relationships (i.e. an employee belongs to a company and a boss) and you can setup the inverse relationships (which is better described with the word 'owns' or 'has', such as 'one company has many employees).
There are many even more complicated relationships depending on your needs and a whole set of delete rules that you can tell the system to follow when an entity in a relationship is deleted. When first starting out I found it easiest to stick with one-to-one and one-to-many relationships like I've described above.
Inheritance
Inheritance is best described as a sort of base template that is used for other, more specific entities. You are correct in stating that you could use inheritance as a sort of protocol to define some basic attributes that are common across a number of entities. A good example of this would be having a base class 'Employee' with attributes 'name', 'address' and 'start date'. You could then create other entities that inherit from this Employee entity, such as 'Marketing Rep', 'HR', 'Sales Rep', etc. which all have the common attributes 'name', 'address' and 'start date' without creating those attributes on each individual entity. Then, if you wanted to update your model and add, delete or modify a common attribute, you could do so on the parent entity and all of its children will inherit those changes automatically.
Managed Object Context (i.e. saving)
Now, onto the other part of your question/statement: wrapping all of your entities into an object which will be used to save and load. You do not need to create this object, core data uses the NSManagedObjectContext (MOC for short) specifically for this purpose. The MOC is tasked with keeping track of objects you create, delete and modify. In order to save your changes, you simply call the save: method on your MOC.
If you post your entities and what they do, I might be able to help make suggestions on ways to set it up in core data. You want to do your best to setup as robust a core data model as you can during the initial development process. The OS needs to be able to 'upgrade' the backing store to incorporate any changes you've made between your core data model revisions. If you do a poor job of setting up your core data model initially and release your code that way, it can be very difficult to try and make a complicated model update when the app is in the wild (as you've probably guessed, this is advice born out of painful experience :)

Core Data - Predict to filter relationship subclass

I have an entity User entity which is a parent entity to a Friend entity.
The User entity has a to-many relationship with an entity named Article.
The idea is there are users saved and also friends (from Facebook), the to-many relationship to Article is set on the User entity as this is being subclassed by Friend.
My question is how can I request all Articles by Friends and not by all users ?
I am having trouble setting an Predict to omit User entities and keep only Friend entities.
Thanks.
Is there a reason you are building a parent/child entity design here? Parent/Child entities come with a really heavy cost if you are persisting to a sqlite store. It is almost always a better idea to just have a single entity and have a flag stating if it is a friend.
Also, I know of no way, at the database level, to filter out the parent from the child in this design. It can be done in memory after the fetch by requesting the entity.name but that will not turn into a sql call properly.

Resources