Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data: 3 table join?

I know Core Data is not a database and there are many differences. Is this one?

In a database, I would commonly have the following

A ->> B ->> C

"A" has many "B" which has many "C"

The query, "Give me all A's which have c.attr = 'X' is easily written like:

select * from a, b, c where a.id = b.aid and b.id = c.bid and c.attr = 'X'

In Core Data, I would like to do the same, but using a predicate like:

NSPredicate *predicate = 
  [NSPredicate predicateWithFormat:@"ANY bs.cs.attr = %@", "X"];
[frequest setEntity:entityA];
[frequest setPredicate:predicate];

Doing this results in the error: 'NSInvalidArgumentException', reason: 'multiple to-many keys not allowed here'

Am I correct to interpret to mean there is a limitation on what databases call multi-table joins?

I googled around and couldn't find a definitive answer.

My current solution to this query looks like:

NSPredicate *predicate = 
  [NSPredicate predicateWithFormat:@"ANY cs.attr = %@", "X"];
...
NSArray *bs = //execute fetch
for (B *b in bs) {
  //add b.a into an array
}
//return array

Is there a better way? Thanks in advance for the consideration.

like image 824
Mike Avatar asked Sep 27 '10 03:09

Mike


1 Answers

Your going about this backwards.

First of all, you don't need the linking ids in Core Data because all related objects are already linked by the relationship. This means constructions like where a.id = b.aid and b.id = c.bid aren't needed at all.

Secondly, you generally set the fetch entity for the entity that receives the defining test. In this case, that is c.attr="X"So, you set your fetch entity to C and your predicate should look something like:

NSPredicate *p=[NSPredicate predicateWithFormat:@"attr=%@",xValue];

This will return an array all the C instances that meet the test. Then finding any particular B or A is just a matter of walking the relationship for each C.

If your inverse relationship is to-one e.g A<->>B<->>C, the you just ask each C for the value of the b.a so:

AObject *anA = aCinstance.b.a;

It's important to remember you are not dealing with tables here. You are dealing with an object graph. You set the fetch to a particular entity and then walk the filtered entities' relationships.

like image 80
TechZen Avatar answered Sep 28 '22 07:09

TechZen