39

I have an NSFetchRequest which is returning the objects' properties in an NSDictionaryResultType. Is it possible to also get the objects' ObjectId within this dictionary? Otherwise I will need to run the query with a return type of NSManagedObjectResultType which is much slower for a large number of returned items.

Jason
  • 14,517
  • 25
  • 92
  • 153

5 Answers5

85

Yes you can, using the very nifty but badly-documented NSExpressionDescription class. You need to add a properly-configured NSExpressionDescription object to the array of NSPropertyDescription objects you set via setPropertiesToFetch: for your NSFetchRequest.

For example:

NSExpressionDescription* objectIdDesc = [[NSExpressionDescription new] autorelease];
objectIdDesc.name = @"objectID";
objectIdDesc.expression = [NSExpression expressionForEvaluatedObject];
objectIdDesc.expressionResultType = NSObjectIDAttributeType;

myFetchRequest.propertiesToFetch = [NSArray arrayWithObjects:objectIdDesc, anotherPropertyDesc, yetAnotherPropertyDesc, nil];
NSArray* fetchResults = [myContext executeFetchRequest:myFetchRequest error:&fetchError];

You should then have a @"objectID" key in the the dictionaries you get back from your fetch request.

Nick Hutchinson
  • 5,044
  • 5
  • 33
  • 34
5
 NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = [NSEntityDescription entityForName:@"yourEntity" inManagedObjectContext:context];
    request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES], nil];
    request.predicate = nil;
    request.fetchLimit = 20;

    NSError *error = nil;
    NSArray fetchedResults = [context executeFetchRequest:request error:&error];

    NSLog(@"%@", [fetchedResults valueForKey:@"objectID"]);

Since your fetched results are already in an array why not pull them out with the valueForKey:@"objectID" ? Clean, simple only need one fetch request so you can pull all other data you need as well.

Michael Shaw
  • 75
  • 1
  • 1
  • 1
    Jason wants results in dictionary format, while your approach returns a faulted managed object – unixo Sep 03 '12 at 10:07
3

Swift Version of the accepted answer

    let objectIDExpression = NSExpressionDescription()
    objectIDExpression.name = "objectID"
    objectIDExpression.expression = NSExpression.expressionForEvaluatedObject()
    objectIDExpression.expressionResultType = .objectIDAttributeType
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: entityName)
    fetchRequest.resultType = .dictionaryResultType
    //
    var propertiesToFetch: [Any] = [objectIDExpression]
    propertiesToFetch.append(contentsOf: entity.properties)
    fetchRequest.propertiesToFetch = propertiesToFetch
Jason
  • 14,517
  • 25
  • 92
  • 153
Ezimet
  • 5,058
  • 4
  • 23
  • 29
1

Nick Hutchinson's answer in Swift:

    let idDescription = NSExpressionDescription()
    idDescription.name = "objectID"
    idDescription.expression = NSExpression.expressionForEvaluatedObject()
    idDescription.expressionResultType = .objectIDAttributeType

I can't comment on it because I don't have enough rep :(

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
ayushn21
  • 305
  • 2
  • 7
-1

The only solution I have found so far is executing a second fetch request, that is similar to the initial fetch request except the following differences:

[fetchRequest setReturnsObjectsAsFaults:YES];
[fetchRequest setPropertiesToFetch:nil];
[fetchRequest setFetchLimit:1];
[fetchRequest setFetchOffset:index]; // The index for which the objectID is needed
[request setResultType:NSManagedObjectIDResultType];

This will cause the fetch request to return an array with exactly one object, the wanted objectID. Performance seems good, even when the initial fetch request's result contains 10000 objects.

If there are any better ways to handle this I would be glad if someone could post them here.

agf
  • 171,228
  • 44
  • 289
  • 238
rsobik
  • 82
  • 2