Core data many to many relationship query - ios

Suppose two entities: EntityA and EntityB, connected by many to many relationship. Suppose the relation attributes are relatedEntityBs and relatedEntityAs respectively. And I have an NSArray of EntityB instances. I want to find all EntityA instances which have in relation all instances that are in nsarray. That is if the array is [entityB1,.....,entityBn]. Find all EntityA instances, which are related with entityB1,wntityB2 till entityBn. How can I write this kind of predicate?

This predicate should do it:
NSMutablArray *predicateArray = [NSMutableArray array];
for (int i=0;i<entityBArray.count;i++){
NSPredicate *subPredicate = [NSPredicate predicateWithFormat:#"ANY relatedEntityBs contains %#",[entityBArray objectAtIndex:i];
[predicateArray addObject:subPredicate] ;
}
NSCompoundPredicate *daddyPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicateArray];
Basically each sub predicate checks if relatedEntityB contains a single object of the array and finally the daddyPredicate combines them all in with OR.

Related

Calling method on object in NSPredicate with Core Data

I have a 'position' entity with a to-many relationship to 'employee's. I want to use NSPredicate to do something like this
[position.employees containsObject:meEmployee]
There is a call to perform NSPredicate with block, but sadly it can't be used with CoreData.
How can I do this?
If you are fetching position entities with any employees matching meEmployee then you can use a predicate like this:
NSPredicate *predicate = [NSPredicate predicateWithFornat:#"ANY employees == %#", meEmployee];
But if the inverse relationship for employees is position, you can achieve the same with:
meEmployee.position

Core Data Fetch Results Reduced Set of Related Items

I have a NSFetchResult that returns managed objects that contain MANY related objects ( Aobj ->> Bobj). The "Bobj" managed object contains a BOOL attribute "isSet" (stored as NSNumber). The NSFetchResult returns all Aobj objects.
I would like a suggestion for an NSPredicate that would return an Aobj with only those Bojs where isSet is TRUE (#1).
Currently, I enumerate over my NSArray of Aobjs returned by my fetch result so that I can get my filtered NSArray of Aobjs this way:
- (NSArray *)filteredObject:(Aobj *)aObj
{
NSMutableArray* bObjs = [aObj.bObjs mutableCopy];
[bObjs enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Bobj* bObj, NSUInteger idx, BOOL *stop)
{
if (bObj.isSet == [NSNumber numberWithBool:NO])
{
[bObjs removeObject:story];
}
}];
return bObjs;
}
Asked another way: how would I define an NSPredicate for my NSFetchResult that would get all my Aobjs but limit the related Bobjs to those matching Bobj.isSet == YES?
Thanks in advance!
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:#"SELF.bObjs.isSet == YES"];
[myFetchRequest setPredicate:myPredicate];
NSArray *array = [moc executeFetchRequest:myFetchRequest error:&error];
Use a subquery. Subqueries follow this general format:
SUBQUERY(relationship, related_thing, predicate)
relationship is the relationship on the object being evaluated.
related_thing is an individual object in the relationship. It's prefixed by a $ and is then used in the predicate (not shown above, for clarity).
predicate is the predicate to apply to related_thing.
With your example, it would look like (assuming your relationship is called 'bobjs'):
SUBQUERY(bobjs, $obj, $obj.isSet == YES)
Subqueries can be quite powerful. For example, you can also apply collection operators to the subquery:
SUBQUERY(bobjs, $obj, $obj.isSet == YES).#count > 1 would give you each AObj that has at least one object in the 'bobjs' relationship with isSet equal to YES. Obviously, you can use other collections operators or layer logical operations or additional expressions on top of this.

CoreData - Fetch request with relationship object

please confirm if i understand that right...
Imagine there is an entity 'person' and an entity 'credit_card'.
So one 'person' can have many 'credit_card's.
The person entity has the attributes: name: STRING and age: INT
and relationship: creditcards (to many) inverse
and the credit card entity has: card_number: INT and valid_date: DATE and relationship: card_user (to one) inverse
In my code i have a specific person (ManagedObject) called f.e. Person *currentUser. If i now want to get all credit cards of this specific person with a specific 'valid_date' i would create a fetch request (for Entity 'credit_card') with following predicates:
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:
#"valid_date == <NSDate object>"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:
#"ANY card_user like currentUser"];
This predicate works well for me, but is that the right way? Should i really ask for: "ANY relationship name like ManagedObject" ?
If I'm understanding what you want correctly, all you need to do is use the creditcards property on your Person *currentUser and filter it down:
NSSet *setOfCreditCards = currentUser.creditcards;
NSPredicate *filter = [NSPredicate predicateWithFormat: #"valid_date == %#", date];
NSSet *cardsWithValidDates = [setOfCreditCards filteredSetUsingPredicate:filter];
The reason you tell CoreData about relationships is to avoid making another query from scratch.
You do not need to use the ANY key word if you have set up you core data model correctly. Specifically Credit cards need to have a person relationship back to the person object (you should get a warning if you didn't do this). Then you could combine both predicates into one like this
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"person == %# AND valid_date == %#", currentUser, valid_date];

NSPredicate for obtaining all Students with a certain Course name?

I have two Entities, Student and Course, where each has a to-many relationship to the other (i.e., a Student has 0 or more Courses, and a Course has 0 or more Students).
I need to obtain all Students who are enrolled in a Course. I also need to obtain all Courses in which a given Student is enrolled (by firstName).
An pseudo-predicate would be: all students who have a course whose name is equal to courseName.
So my question consists of two parts:
What is a valid NSPredicate for obtaining all students with a certain course name?
What is a valid NSPredicate for obtaining all courses where a student with a certain firstName is enrolled.
For your reference, here are my entities:
1) Use this to filter an array of students that are in a specific course with courseName :
[NSPredicate predicateWithFormat:#"ANY courses.name like %#", courseName]
Alternatively, if you already have a course object (and name is unique in call course objects), you can simply get all of its students by accessing its students property, i.e.
course.students // returns an NSSet/NSOrderedSet based on your model setup
2) Use this to filter an array of courses that have a student with a certain firstName :
[NSPredicate predicateWithFormat:#"ANY students.firstName like %#", firstName]
Note: NSSet and NSOrderedSet have a method array to get an array of the objects.
See also the docs on NSPredicate under Using Predicates with Key-Paths.
What is a valid NSPredicate for obtaining all students with a certain course name?
[NSPredicate predicateWithFormat:#"name= %#", courseName];
Use above predicate to fetch particular course while has name = courseName;Set that predicate on "Course" entity not "Student" entity.
AFter executing above fetch request, you will have array of courses having that courseName.
Course *course = [fetchedResults objectAtIndex:0];
Now to get all students in that course,
NSArray *students =[course.students allObjects];
now students is an array of "Student" entity objects.
Similarly ,
What is a valid NSPredicate for obtaining all courses where a student with a certain firstName is enrolled.
[NSPredicate predicateWithFormat:#"firstName = %#", name];
Use above predicate to fetch particular student who has name = firstName;Set that predicate on "Student" entity.
AFter executing above fetch request, you will have array of students having that firstName.
Student *student = [fetchedResults objectAtIndex:0];
Now to get all courses for that student,
NSArray *courses =[student.courses allObjects];
now courses is an array of "Course" entity objects.
Hope this helps.

How to use Core Data relationship?

In my app I have 3 related entities. Athlete, Exercise, and Exercise Score.
Athlete has a to-many relationship with Exercise. It's inverse is whosExercise.
Exercise has a to-many relationship with exercise score. It's inverse is whichExercise.
I want to perform a fetch request where I get all the exercise scores for an athlete. How would I get that? Do I need another relationship between Athlete and Exercise Scores, or is that redundant? If it is, how would I use exercise as a predicate for my request?
If Exercise has a relationship to Athlete, then you should be able to do something like:
[NSPredicate predicateWithFormat:#"SELF.athlete = #%", currentAthlete];
and then just:
[Exercise fetchByPredicate:currentAthletePredicate];
Should be it.
If I clearly understand, you need to select all ExerciseScore for Athlete, but Athlete does not have direct relationship with ExerciseScore table.
SLQ Query for this may looks like :
Select *
from ExerciseScore
where IDScore in (select IDScore
from Exercise
where IDExercise in ( select IDExercise
from Athlete
)
)
But in Core Data you can't operate SLQ Queries.
Try this approach.
1.Fetch all Exercise for Athlete:
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Exercise"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.athlete = #%", currentAthlete];
request.predicate=predicate;
NSArray *athleteExercises = [self.managedObjectContext executeFetchRequest:request error:&error];
2.Iterate throughout array of Exercises to get all Exercise score for each Exercise.
NSMutableArray *allScores = [NSMutableArray arrayWithCapacity:0];;
for (Exercise *exercise in athleteExercises) {
if ([exercise.scores count]>0) {
[allScores addObjectsFromArray:[exercise.scores allObjects]; //exercise.scores must be NSSet type
}
}
allScores array now contain All ExerciseScore objects for particular Athlete.
Predicates can have key paths:
#"whichExercise.whosExercise = %#",athlete
Or, if you have the athlete already, don't do a fetch request, just get the scores via the relationship properties.

Resources