views:

385

answers:

3

I have the need to create a complex predicate for an abstract base object. I want to have separate predicate queries for different inheriting entities and key off the sub-entity type, the example below is what I would like to do, however, I have not been able to find a way to reference the entity name or type in the predicate.

NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"MyCommonObjectBase" inManagedObjectContext:myContext];

NSPredicate *subclassAPredicate = [NSPredicate predicateWithFormat:@"someValue > %@ && entityName = %@", 100, @"SubclassA"];
NSPredicate *subclassBPredicate = [NSPredicate predicateWithFormat:@"someValue < %@ && entityName = %@", 50, @"SubclassB"];

request.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:[NSArray arrayWithObjects:subclassAPredicate, subclassBPredicate, nil]];
+1  A: 

A shot in the dark here, but what about using the className value in the predicate?

NSPredicate *subclassAPredicate = [NSPredicate predicateWithFormat:@"someValue > %d AND child.className = %@", 100, @"SubclassA"];

(Notice that you had an error in your predicate format. You were using %@ to try and substitute in an integer value (100). %@ is only used for objects. Use %d (or some other flavor) for primitives)

EDIT Found it!

You'll want to do this:

NSPredice * p = [NSPredicate predicateWithFormat:@"entity.name = %@", @"SubclassA"];

I just tested this on one of my apps and it seems to work.

-Another edit-

Here's the test that I ran, which seemed to work:

NSManagedObjectContext * c = [self managedObjectContext];
NSFetchRequest * f = [[NSFetchRequest alloc] init];
[f setEntity:[NSEntityDescription entityForName:@"AbstractFolder" inManagedObjectContext:c]];
[f setPredicate:[NSPredicate predicateWithFormat:@"entity.name = %@", @"DefaultFolder"]];
NSError * e = nil;
NSArray * a = [c executeFetchRequest:f error:&e];
[f release];
NSLog(@"%@", a);

When I run that, a logs two NSManagedObjects, both of the @"DefaultFolder" variety (which is what I was expecting). (AbstractFolder is an abstract entity. One of the child entities that inherits from it is a DefaultFolder)

Dave DeLong
I'll give that a shot, thanks. Yeah, that's a typo from generalizing some production code for the sake of illustration.
Greg Martin
No luck, className is not a valid keypath. Also, I'm looking for the entity name of self not a child entity just to clarify.
Greg Martin
@Greg I found a way that works and edited my answer.
Dave DeLong
I don't see the same result, when I add that I still get an error with message "keypath entity.name not found in entity".
Greg Martin
Did you do this in an iPhone app or Mac app? I wonder if there is a difference in the Core Data implementation.
Greg Martin
@Greg - I just tried it w/ an iPhone app and found something curious. It will work if your store type is NSBinaryStoreType, but not if it's NSSQLiteStoreType. My code above was running on an NSXMLStoreType. I'll keep looking for a way to do it on a SQLiteStoreType.
Dave DeLong
I have submitted a bug report to Apple on this, hopefully they can fix it at some point.
Greg Martin
A: 

The only way of associating a predicate with an entity I know of like is this:

NSPredicate * predicate = [NSPredicate predicateWithFormat: @"(%K == %@)", fieldName, fieldValue, nil];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]];
[request setPredicate:predicate];

Maybe you were referring to the field name?

Edit: the entity is associated with the request, not with the predicate.

Elraij
+1  A: 

I got a response from Apple at http://bugreport.apple.com problem number 7318897:

entity.name is not a modeled property, so it's not legal. it works by accident on the binary store. The correct way to fetch subentities is to do so on the NSFetchRequest and use either setIncludesSubentities or not.

So it seems the proper solution is to have separate fetch requests and to merge the result sets after execution.

Greg Martin