views:

193

answers:

2

Hi guys,

I have an object NetworkMember that has no attributes but is defined by its relationships Person, Network, Level and Role. In my app, I've found all the four relationships, but I want to make sure not to double-register my NetworkMember, thus I'd like to search for this NSManagedObject before instantiating it.

How should I write a query that queries for an NSManagedObject just consisting of relationships?

Cheers

Nik

+1  A: 

You can use an NSPredicate with key-value paths to refer to the relationships as the predicate to an NSFetchRequest. For example:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntity entityForName:@"NetworkMember" inManagedObjectContext:managedObjectContext];
[request setPredicate:[NSPredicate predicateWithFormat:@"person.name == %@ AND ANY (roles.name == \"Manager\")", name]];
NSInteger count = [managedObjectContext countForFetchRequest:request error:&error];
[request release];
if (error) { /* handle the error */ }
if (count != 0) { /* do something if the member already exists */ }

If all you need is to confirm the existence of a particular object, you can use the method countForRetchRequest:error: to see how many objects would be returned if you execute the fetch request. If you're doing this test a lot, this can be much more efficient.

Alex
So it's not possible to query by the IDs that Core Data otherwise uses behind the scenes in the SQLite3 db?
niklassaers
Your data is not necessarily stored in a sqlite database. Core Data also supports XML and binary formats, so it's not accurate to think of Core Data as a database. Core Data does have the `NSManagedObjectID` class to uniquely identify each object, and there are methods you can use to get objects based on those IDs.
Alex
You should not rely on the `-objectID` attribute because it can and does change. The only time you should be using it is when you are passing references between threads. Other than that do not rely on it. If you need a unique create your own.
Marcus S. Zarra
+2  A: 

You can write an NSPredicate against relationships just as you would against attributes.

For example:

- (BOOL)isPerson:(Person *)person memberOfNetwork:(Network *)network {
    // assume NetworkMember entity is ivar networkMemberEntity_
    // assume NSManagedObjectContext is ivar context_

    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    [fetch setEntity:networkMemberEntity_];
    [fetch setPredicate:[NSPredicate predicateWithFormat:
        @"(person == %@) AND (networks CONTAINS %@)", person, network]];
    [fetch setFetchLimit:1];

    NSError *error = nil;
    NSInteger count = [context_ countForFetchRequest:fetch error:&error];
    if (count < 0) {
        // always handle errors in real code
        // and never check for errors using "error == nil"
    }

    return count > 0;
}

In the case you present, however, you should strongly consider whether you really need to do this. It sounds like you're trying to model a many-to-many relationship between Person and Network. If you come from a database background you might think you need a join table for this, and make an intermediate entity.

However, Core Data can manage all of that for you; you can create a many-to-many relationship directly between Person and Network and not have to maintain any intermediate entity or table yourself. Just like how you don't have to worry about primary and foreign keys when dealing with relationships in Core Data, the framework deals with that kind of thing for you, letting you work at the object level.

Chris Hanson
Thank you very much, this is the way I hoped it could be done. :-)
niklassaers