Irfan DANISH
Irfan DANISH

Reputation: 8489

CoreData NSPredicate with relationship

I have following CoreData objects Model

enter image description here

Now I am having issue in making a predicate with following conditions.

Fetch all those DBOpportunity WHERE

DBOpportunity.stateCode == 1

AND

DBOpportunity.invoiceDate >= GIVEN_DATE

AND

DBOpportunityLines.crmAccept == 1 OR DBOpportunityLines.crmAccept == 3

I have tried lots of examples and programming guide by the apple but can't able to achieve this.

Upvotes: 0

Views: 258

Answers (3)

Martin R
Martin R

Reputation: 539685

opportunitylines is a to-many relationship, so there are multiple DBOpportunityLines objects for one DBOpportunity object. Assuming that the last condition

DBOpportunityLines.crmAccept == 1 OR DBOpportunityLines.crmAccept == 3

should hold for any of the related objects, you need a SUBQUERY:

NSDate *givenDate = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"stateCode == 1 AND invoiceDate >= %@ "
    "AND SUBQUERY(opportunitylines, $x, $x.crmAccept == 1 OR $x.crmAccept == 3).@count > 0",
    givenDate];

Remark: Unfortunately, the usage of SUBQUERY in predicates is poorly documented. There is one example in the NSExpression class reference. See also Quick Explanation of SUBQUERY in NSPredicate Expression.

Upvotes: 3

Marc
Marc

Reputation: 6190

The structure of your predicate is A && B && (C || D)

Setup your predicates

NSPredicate *aPredicate = [NSPredicate predicateWithFormat:@"stateCode == %d", value];
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"invoiceDate >=  %@", givenDate];

Similar do the cPredicate and dPredicate. Then first combine c and d with OR

NSArray *cdPredicateArray = @[cPredicate, dPredicate];
NSPredicate *cdPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:cdPredicateArray];

and then all of them with AND

NSArray *allPredicateArray = @[aPredicate, bPredicate, cdPredicate];
NSPredicate *allPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:allPredicateArray];

If I misunderstood your question and your structure is A && B && C || D Then you have to combine A, B and C first (with AND) and then combine that result with D (with OR).

Upvotes: 2

gasparuff
gasparuff

Reputation: 2295

You could also fetch your opportunityLines and then get the parent entities like this:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"opportunityLines" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSDate *yourDate = [NSDate date];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(crmAccept==1 OR crmaccept==3) AND opportunity.stateCode==1 AND opportunity.invoiceDate>=%@", yourDate];
[fetchRequest setPredicate:predicate];

NSError *error;

//So here you have your array of opportunitylines
NSArray *opportunityLines = [context executeFetchRequest:fetchRequest error:&error];

//And this is how you get your opportunity objects
NSArray *opportunities = [opportunityLines valueForKeyPath:@"@distinctUnionOfObjects.opportunity"];

Upvotes: 1

Related Questions