What's better way to build NSPredicate with to-many deep relationships? - iphone

I have three entities: EntityA, EntityB and EntityC connected with to-many relationships.
See schema for details:
alt text http://img706.imageshack.us/img706/9974/screenshot20091220at124.png
For getting all instance of EntityA which depend from EntityB.name I use the predicate like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY EntityB.name like 'SomeName'"];
What should be predicate for getting all instance of EntityA which depend from EntityC.name?
I tried query like #"ANY EntityB.entitiesC.name like 'SomeName'" but get exception "multiple to-many keys not allowed here".
Best regards,
Victor

My final solution is to use SUBQUERY.
NSPredicate *p = [NSpredicate predicateWithFormat:#"(name like %#) AND (0 != SUBQUERY(entitiesB, $x, (0 != SUBQUERY($x.entitiesC, $y, $y.name like %#).#count)).#count)", nameA, nameC];
Unfortunately I was unable to expand this query on nsExpression objects.

While I was stopped at the following decision:
First, I get all the EntityC that satisfy the condition EntityC.name equal to 'SomeName'
NSPredicate *p = [NSPredicate predicateWithFormat:#"name like %#", #"SomeName];
...
NSArray *res = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
Then I get an array of EntityB from above query
NSArray *parentBs = [res valueForKeyPath:#"#distinctUnionOfObjects.parent"];
Than get array of EntityB that satisfy the condition EntityB.EntitiesC.name equal to 'SomeName':
NSExpression *leftExpression = [NSExpression expressionForEvaluatedObject];
NSExpression *rightExpression = [NSExpression expressionForConstantValue:parentBs];
NSPredicate *p = [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression: rightExpression modifier:NSDirectPredicateModifier type:NSInPredicateOperatorType options:0];
I repeat the same for EntityA.
The effectiveness of this solution in doubt and I still expect a better solution for this problem.

Related

NSpredicate to filter the Array of Elements that has substrings

I have written NSPredicate to filter the elements .
-(void)filterResult:(NSMutableArray*)array
{
search=TRUE;
filteredCategoryList=[[NSArray alloc]init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"roles beginsWith %# || UserResponseDetails IN %# ",array,array];
filteredCategoryList = [MembersList filteredArrayUsingPredicate:predicate];
[filteredCategoryList retain];
}
The Problem is I am getting one of the string like "sample;Example" in Roles and others are single string. How to write the Predicate condition to get the Element for Sample,Example,sample and Example.
.
I got a solution that I have to use 'contains' keyword instead of 'beginswith' in the predicate.

Search Core Data for all objects with an empty "to-many" relationship

In an almost identical situation to this question, only I'm looking for all records of one type that are not in any to-many relationship with another type.
So let's say I've got a set of patients, and a set of lists. Patients can belong to multiple lists, and a list can contain multiple patients.
How do I find all of the patients that aren't on any list?
I'm using a Core Data model.
UPDATE: Figured it out, but since I have <100 reputation, I can't answer my own question. Here's what I did:
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"lists.#count == 0"];
[fetchRequest setPredicate:predicate];
Then when I ran the fetch request, it only brought up the patients with no list attached.
Here's what you should do:
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"lists.#count == 0"];
[fetchRequest setPredicate:predicate];
;) wonder where I came up with that solution...
Figured it out. Here's what I did:
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"lists.#count == 0"];
[fetchRequest setPredicate:predicate];
Then when I ran the fetch request, it only brought up the patients with no list attached.

Configuring an NSPredicate with multiple conditions

I'm not certain how one would go about "cascading" several conditions into an NSPredicate.
I'm fairly new to Core Data and not sure if that's the right way to achieve what I am looking to do.
Here is what I am trying to do:
There is a Photo object that has a whereTook relationship to a Location object, which has an inverse of photosTookThere.
The Photo in turn has an NSNumber attribute called isFavourite.
I'd like to configure an NSFetchRequest that will first check that photosTookThere exists and if so, check each resulting Photo object and return only the ones that are set as favourites.
Here is the code so far:
request.entity = [NSEntityDescription entityForName:#"Location" inManagedObjectContext:context];
request.sortDescriptors = [NSArray arrayWithObject[NSSortDescriptorsortDescriptorWithKey:#"locationId" ascending:YES]];
request.predicate = [NSPredicate predicateWithFormat:#"photosTookThere.#count != 0"];
How would I cascade the second condition into the predicate and return the correct results?
Just put each condition inside of parentheses and connect them with AND.
[NSPredicate predicateWithFormat:#"(photosTookThere.#count != 0) AND (isFavourite == %#)", [NSNumber numberWithBool:YES]];
I'd also recommend changing the name of your "whereTook" relationship to "location", and your "photosTookThere" to simply "photos", that's more in line with convention.
I eventually was able to solve this using a subquery:
request.predicate = [NSPredicate predicateWithFormat:
#"(photosTookThere.#count !=0) AND SUBQUERY(photosTookThere, $Photo, $Photo.isFavourite==1).#count >0"
];
You can very simply use AND and OR in your predicate much like you would if you were specifying a "where" condition in an SQL statement. To check for a NULL, which it looks like you want when comparing against "whereTook", you can compare to nil (whereTook = nil).

NSPredicate for fetching keywords that are in a string

In core data I have an entity called keyword with a property 'text'. I want to find all keyword objects that are contained in a particular sting.
I tried:
[NSPredicate predicateWithFormat:#"%# contains[c] text", myString];
But that crashes. It seems like if it will only work if it's reversed.
The predicate works on the entity, so you have your predicate reversed. Since your entity's text property contains a single word, you'd split the string into multiple words and then test:
// This is very simple and only meant to illustrate the property, you should
// use a proper regex to divide your string and you should probably then fold
// and denormalize the components, etc.
NSSet* wordsInString = [NSSet setWithArray:[myString componentsSeparatedByString:#" "]];
NSPredicate* pred = [NSPredicate predicateWithFormat:#"SELF.text IN %#", wordsInString];
I think you're doing in reverse direction.
Try this.
[NSPredicate predicateWithFormat:#"text contains[cd] %#", myString];

Why does the LIKE[c] in my subquery predicate not match this name?

I have two entities: Department and DepartmentInfo. Every Department has one or many DepartmentInfo Objects. Inside DepartmentInfo, there is an departmentName attribute.
I want to fetch all those Department objects which have a specific departmentName. So I make an NSFetchRequest for the Department entity, and use this fetch request:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(departmentName, $s, $s.departmentName LIKE[c] %#).#count > 0", #"Marketing"];
It works, BUT: The LIKE[c] doesn't! I must match against the exact department name. If I do this, I will get no match:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(departmentName, $s, $s.departmentName LIKE[c] %#).#count > 0", #"Mar"];
What could be wrong here?
Since Jason Coco didn't post this as answer, I do it:
Use #"Mar*" and you will match
The use of SUBQUERY here is unnecessary. You can achieve the same results using:
ANY departmentInfo.departmentName LIKE[c] 'Mar*'
Execute that against an array of Department objects and it'll work.