Core Data - Breaking A Relationship - iphone

I have a Patient entity and a List entity. A Patient can belong to several different lists and a list can have several different patients.
Say I have a patient who belongs to 3 lists (A, B, C). I want to remove the patient from lists A & B. I do not want to delete lists A & B themselves though obviously. How do I go about doing this?

While Tim's answer above is technically correct, it seems like quite a bit of code to me.
I would assume that to remove a patient from the list, you already know that list and have a reference to it at the time you want to remove the patient. Therefore, the code can be as simple as:
id myPatient = ...;
id myList = ...;
[[myPatient mutableSetValueForKey:#"lists"] removeObject:myList];
This is of course assuming that your relationships are bi-directional. If they are not then I strongly suggest you make them bi-directional.
Lastly, because this is a many to many relationship, you can execute the above code in either direction.
[[myList mutableSetValueForKey:#"patients"] removeObject:myPatient];
update
Then the code is even simplier:
[myPatient setLists:nil];
That will remove the patient from all lists.

So in order to model this relationship, you have a many-to-many relationship between Patient and List. Let's say that in Core Data, this is represented by a patients relationship on List, with the inverse lists relationship on Patient. Furthermore let's assume that List has some property name with the name of the list, as an NSString.
In order to "break" the relationship (remove a Patient from some Lists), you'll have to have a reference to the Patient NSManagedObject that is to be removed, and the Lists you want to remove that Patient from. Then, all that remains to be done is get a mutable set of the patients for each list, and remove the desired patient:
// Assuming you have some PatientManagedObject *patient:
NSSet *patientLists = [patient lists]; // Set of ListManagedObjects
for(ListManagedObject list in patientLists) {
if([[list name] isEqualToString:#"A"] || [[list name] isEqualToString:#"B"]){
// Now you have to build the set of patients without this patient
NSMutableSet *listPatients = [list mutableSetValueForKey:#"patients"];
[listPatients removeObject:patient];
}
}
For more data, see the relevant Core Data documentation.

Related

Entity Framework - best practice to get count

I have a Customer table and another Orders table. Each Customer can have many orders (One to many relationship).
I want to get a Customer object and from it get how many orders he has (the actual order data is not relevant at this point). So as I see it I have 2 options:
create a view with another OrdersCount field - and that will be another object in my system.
in my app, when I need the count get the Customer.Orders.Count - but for my understanding that will cause an extra query to run and pull all the orders from the database to that collection.
Is there a correct way to do such thing?
Thanks
You do need a new type, but you don't need to recreate all relevant properties.
from c in context.Customers
// where ...
select new {
Customer = c,
OrderCount = c.Orders.Count()
}
Update code that looks for e.g. the Name property of an item in the result, to look for Customer.Name.

Core data cross referencing two relationships

I have a data structure in Core Data like so...
User
Item
Category
User has a toMany relationship "FavouriteItems" to the Item entity.
Category also has a toMany relationship "Items" to the Item entity.
The user can select favourite items from any categories they wish. At the moment I am listing all the items and then displaying the Category alongside.
What I'd like to do is display all the user's favouriteItems for a selected Category.
i.e. select all the Items that have a relationship with Category x and User y.
I'm currently doing this by getting all the Items through one relationship (i.e. User.favouriteItems) and then filtering the NSSet using a block predicate.
Is it possible though to do this with a simple CoreData predicate?
Hmm... thinking about it would a predicate like this work...
[NSPredicate predicateWithFormat:#"interestedUser.id = %# AND category.id = %#", user.id, category.id];
And then run a fetch request on the item entity?
Would that work?
Shooting pretty blind as that's an awkward scenario to set up just to answer a question but perhaps
If you are filtering an array of Items which has the correct inverse relationships set up.
[NSPredicate predicateWithFormat:#"%# IN interestedUsers AND %# IN categories",
someUser,
someCategory];
Basically the Item has many users (interestedUsers) so we are saying is our user in this collection.
Similarly the Item has many categories (categories) so we are saying AND is our chosen category in this collection.

CoreData Guidance

So I have this problem I am trying to solve - I wonder if anyone can comment on/help me with the approach. The thing is, I have it partly solved, but with the rest I'm not quite sure.
Here's the deal:
I have a fairly large DB online which I want to load on first start of the App. After that I am only going to load it if new versions exist.
I use an xml parser to parse the data and enter all the data to my data model. The database consists of thousands of products, all described by various attributes.
Anyway, it's easy for me to save thousands of products in a database, then retrieving the data on demand.
I have a problem of how to categorize them and how to save the category data. There is a main category i.e. Hi-Fi which has several subcategories- let's say 'stereo', 'tuner', 'phone' and so on....
How to best save this info, that category a has 15 subcategories and each of these categories in turn has 30 products while securing performance and keeping process-time at a minimum. I don't want to check all 2000 Products whether I need to show them in a certain table view each time I open a new table view.
Any hints on the apporach are appreciated.
You'll need two entities: Product and Category.
Category has a to-many relationship called subcategories with a target entity of Category. The inverse relationship can be called parentCategory. Category also has a to-many relationship called products. Product would have an inverse relationship called category (or categories if a product can belong to multiple categories)
Now, you can get all the products for a given category by checking its products property. If you want to include all the products in the subcategories, you can do a fetch request with a predicate like this:
[NSPredicate predicateWithFormat:#"category == %# OR category IN %#", category, category.subcategories];
I think you can solve it by having a Core Data modal consisting of three entities: Product, Category and SubCategory.
Product has a relationship category with destination Category and a relationship subcategory with destination SubCategory.
Category has a to-many relationship products with destination Product and a to-many relationship subcategories with destination SubCategory.
SubCategory has a to-many relationship products with destination Product and a relationship category with destination Category.
When defining these relationships remember to assign the Inverse relationships as well.
Now you get a list of all products belonging to a specific category by just loading the Category in question and accessing the products property. It should also be possible to use NSFetchRequest for Product with a predicate specifying which category you want. Which is best regarding performance and memory requirements I can't say so you just have to test which approach works best.

Core data many-to-many relationship - Predicate question

In my Core Data model I have two entities: List and Patient. List has an attribute called 'name'.
A List can have any number of Patients and each Patient can belong to any number of different lists. I have therefore set a relationship on List called 'patients' that has an inverse to-many relationship to Patient AND a relationship on Patient called 'lists' that has a to-many relationship to List.
What I'm struggling to figure out is how to create a Predicate that will select all Patients that belong to a particular List name.
How would I go about this? I have never used relationships before in Core Data.
This seems to work OK:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(ANY lists == %#)", myList];
Where myList is an actual List entity.
Given a data model like:
List <<——>> Patient,
you can find all Patient instances that belong to a list with a particular name with a fetch request on the Patient entity using a predicate like:
[NSPredicate predicateWithFormat:#"ANY lists.name LIKE[cd] %#", listName]
assuming listName is an NSString instance with the list name you want. LIKE[cd] does a case-insensitive and diacritic-insensitive comparison.
It sounds like your data model is this:
List <<-->> Patient
I would think that if you know the particular list name, then you know the particular list object. If so, you can just grab the patients using the to-many relationship from List to Patient--it is a set of patient objects. For example, if the relationship from List to Patient is named "patients":
NSSet *patientSet = listObject.patients;
Note: this requires that you create subclasses for your managed objects so you can access the attributes and relationships as properties on your objects.
If you only know the list name for some reason, and you are fetching Patient objects, then you can create a predicate using the to-many relationship from Patient to List (assume it's named "lists" and the list's name in a string named "listName"):
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY lists.name == %#",listName];
Ten years later, some more info !
Just some more info on the fantastic #GarryPettet answer,
Say you have entity CD_Person and aPerson is one of those. IE:
var aPerson: CDPerson
Say you have an entity CD_Pet
CD_Person has a relationship .pets which is a one-to-many CD_Pet
So just to be clear,
aPerson.pets
is indeed a Set of CD_Pet entities.
Almost certainly you'll have an id field which comes from your data source.
(Aside, .id must be an Int64 in your core data entity, even if it's a smaller int in your source data)
Two ways to go!
BOTH this
let p = NSPredicate(format: "(ANY pets == %#)", aPerson )
AND this
let p = NSPredicate(format: "(ANY pets.id == %lld)", aPerson.id)
... work perfectly, both are possibilities.
So there's two ways to go!
(PS: Don't forget the lld .. # won't work for Int64!)
Both work fine in the common situation where you have a "many-to-many" relationship.

Core Data - Associate a Quantity to a Relationship

I have a Core Data entity called "Item" and it represents an item in a store so it has a name, price, and a few other attributes.
I would like to be able to create lists of these items and I am having some trouble figuring out how to do it.
The problem is that I need to be able to associate a quantity for each item in the list AND I need to be able to add the item to multiple lists.
So for example, say I have an item called "Bread" and I want to add it to two different lists with different quantities associated with each relationship.
I see that the documentation for Core Data says that a userInfo dictionary can be associated with a relationship but I can't seem to locate any information that would indicate whether or not that would work for me.
Any ideas?
This is probably not the best place for a userInfo dictionary. Instead, create a new entity, which has a list releationship, an item relationship, and a quantity attribute. When you add Bread to a list, you actually add this 'link' object, and hook up the Item and List relationships, then set its quantity.