Core Data Fetch Request Variable in Xcode 4 - ios

How do I add a variable to a fetch request in core data in Xcode 4? Can't find it.

Select Expression from the drop down and enter the expression using a $ before your substitution variable (NAME in the example below). Even if the substitution variable's value is a string, make sure you don't put the variable between quotes, or the substitution will not work.
In your code you refer to the fetch predicate like this (XCode 4.4 and above):
NSManagedObjectModel* model = [[context persistentStoreCoordinator] managedObjectModel];
NSFetchRequest* request = [model fetchRequestFromTemplateWithName:templateName
substitutionVariables:#{#"NAME" : name}];
NSError* error = nil;
NSArray* results = [context executeFetchRequest:request error:&error];

Apple has moved it again in the latest XCode. To use Variables in the Fetch Requests in the Core Data editor, you have to use the "expression" type and manually type it in:
data == $DATA
(in this expression, $DATA is the variable).

If by variable you mean pass a value to a fetch request so you delimit the request? Then all you do is declare an NSPredicate.
Something like this:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"name" inManagedObjectContext:context];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(attribute == %#)", value];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error;
NSArray *results = [context executeFetchRequest:request error:&error];
[request release];

You may have already found a solution but it took me a while and it may save someone else's time so here it is: the apple documentation explains it.

Related

executeFetchRequest is not working with propertiesToFetch

I have integrated coreData in my application. I am running NSManagedObjectContext in the main thread.
-(NSArray *) getResultForContext:(NSManagedObjectContext *)context
{
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:#"Person"];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Person" inManagedObjectContext:context];
[request setEntity:entity];
NSError *fetchError;
NSArray *allObjects = [self executeFetchRequest:request error:&fetchError];
return allObjects;
}
The above method is working fine but if I add propertiesToFetch to the request, executeFetchRequest return an empty array.
-(NSArray *) getResultForContext:(NSManagedObjectContext *)context
{
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:#"Person"];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Person" inManagedObjectContext:context];
[request setEntity:entity];
[request setResultType:NSDictionaryResultType];
[request setReturnsDistinctResults:YES];
[request setPropertiesToFetch:#[#"firstName",#"lastName"]];
NSError *fetchError;
NSArray *allObjects = [self executeFetchRequest:request error:&fetchError];
return allObjects;
}
This method returns an empty.
What is missing here?
Assuming that (1) data is present (i.e. that there actually are some Person instances to be fetched) and that (2) the result is actually an empty array and not nil:
The only way I know to get a non-empty array in the first case but an empty array in the second case would be if the listed properties are both nil for all instances. In that case, there are no values, so the call to setReturnsDistinctResult effectively filters out every result (because nil is not considered a distinct result).
If either property is non-nil for any existing Person instance, you'll get a non-empty array. But if there are no property values to fetch, there are no distinct results, and the result is empty.
If it happens that the result is actually nil, and not an empty array, look at fetchError for clues.
The problem comes from the NSDictionaryResultType.
As said bbarnhart on this post, you must save the context to persistent store before using the resultType NSDictionaryResultType.
Be careful to the declaration of the context persistentStoreCoordinator too.

NSManagedObjectID returns a string while requesting distinct NSManagedObject

I am trying to request distinct results using my NSFetchedResult. I tried to use the answer posted here: What class is returned when requesting distinct NSManagedObject property instances from Core-Data? to use the NSMangedObjectID in order to get the actual NSManagedObject. Here is the NSFetchedResult code:
//Unique fetch request
NSFetchRequest *uniqueFetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"EntityName"];
[uniqueFetchRequest setPropertiesToFetch:#[#"name"]];
[uniqueFetchRequest setReturnsDistinctResults:YES];
[uniqueFetchRequest setResultType:NSDictionaryResultType];
[uniqueFetchRequest setPredicate:predicate];
[uniqueFetchRequest setSortDescriptors:sortDescriptors];
uniqueResults = [[NSArray alloc] initWithArray:[context executeFetchRequest:uniqueFetchRequest error:&error]];
NSManagedObjectID *mid = uniqueResults[0][#"name"];
EntityData *card = (EntityData *)[context objectWithID:mid];
However, [uniqueResults[0][#"name"] is returning a NSString with the actual name of the NSManagedObject it found rather than something like 0x8b7b120 <x-coredata://C7E53293-94C7-444D-8162-167B1D66A961/Hair/p33> (which is what was returned in the link I posted). Because it is now a NSString, [context objectWithID:mid] crashes and gives me the following error: [__NSCFString persistentStore]: unrecognized selector sent to instance 0xc47b170
What am I doing wrong here?
Take a look at the collection operators
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"EntityName"];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:sortDescriptors];
results = [context executeFetchRequest:fetchRequest error:&error];
uniqueResults = [results valueForKeyPath:#"#distinctUnionOfObjects.name"];
Your mistake here is trying to treat your name (NSString property) as a relationship.
Your request will return all distinct name attribute values (existing for the EntityName entity) in an array of dictionaries.
If 2 (or more) objects could have the same name, which object ID do you expect to get back?
If you want to segment your data based on a property value, I would suggest you use a NSFetchedResultsController and specify the sectionNameKeyPath: to match your needs.
Edit:
If your OK with unstable results you could try:
NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:#"Ingredient"];
r.resultType = NSDictionaryResultType;
r.propertiesToGroupBy = #[#"name"];
NSExpressionDescription* objectIdDesc = [[NSExpressionDescription alloc] init];
objectIdDesc.name = #"objectID";
objectIdDesc.expression = [NSExpression expressionForEvaluatedObject];
objectIdDesc.expressionResultType = NSObjectIDAttributeType;
r.propertiesToFetch = #[objectIdDesc,#"name"];
NSArray* res = [context executeFetchRequest:r error:nil];
But I see no use for this kind of fetch

How To Format NSPredicate when doing an "IN" search with Coredata and NSFetchRequest

I have a very simple fetch request that i want to execute. One of my entities has an attribute called smartCollectionIds and it is of type transformable. I use this attribute to store an NSArray of simple strings. In my code i use an NSfetchedResultsController to populate a tableview. The predicate im using is as follows:
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
however this causes a crash, specifically at the pint when i perform a fetch. However, if i first use a fetch to load all my objects into an array, and then filter them out with the above predicate, the app does not crash, and i get my results as expected. So basically
THIS CODE BELOW DOES NOT WORK
-(void) tryTO
{
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Tweetary" inManagedObjectContext: [[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse]];
NSPredicate *predicate;
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
NSSortDescriptor *secondarySortKey = [[[NSSortDescriptor alloc] initWithKey:#"created_at" ascending:FALSE] autorelease];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease] ;
[request setEntity:entity];
[request setPredicate:predicate];
[request setSortDescriptors:[NSArray arrayWithObjects:
secondarySortKey
,nil]];
[request setFetchLimit:30]; //30
NSError *error;
NSArray *results = [[[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse] executeFetchRequest:request error:&error];
if (error != nil)
{
NSLog(#"Results are %d",[results count]);
}else{
NSLog(#"findAllObjectsInContext error %#",error);
}
}
BUT THIS WORKS
NSArray *tweets = [Tweetary findAllObjectsInContext:[[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse]];
NSLog(#"Before filter count is %d",[tweets count]);
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
predicate=[NSPredicate predicateWithFormat:#"smartCollectionIds!=nil && (%# IN smartCollectionIds)",#"87F173A5-863D-4ECE-9673-A61D8F1E01FC-6285-000009A9CBAF3290"];
NSArray *bNames = [tweets filteredArrayUsingPredicate:predicate];
NSLog(#"FINAL Results %d",[bNames count]);
+ (NSArray *)findAllObjectsInContext:(NSManagedObjectContext *)context;
{
#synchronized(self){
NSEntityDescription *entity = [self entityDescriptionInContext:context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entity];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
if (error != nil)
{
//handle errors
//NSLog(#"findAllObjectsInContext error %#",error);
}
return results;
}
}
In a nutshell, i need my fetch predicate to work when using NSfetchedResultsController instead of first loading up my objects into an array, and then applying my filter predicate. Can anyone point me in the right direction/ figure out why the predicate works only after i load my unfiltered data set into an array?
A Core Data fetch request with a predicate is translated to a SQLite query and executed
on the SQLite level. A transformable array is stored as some blob in the SQLite database,
therefore treating it as array in a fetch request does not work.
If you fetch the elements first, the blob is transformed back to an array
when the property is accessed. Therefore filtering the array of fetched objects works as expected.
I don't think there is any workaround. You cannot filter on transformable properties
in a fetch request.

Search Core Data Users By Name

I am trying to get a list of users whose names were selected from a tableview and stored in the array selected.
What's wrong with my code? Sorry this is my first time with CoreData so I don't really know what's wrong.
NSFetchRequest *request= [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"AUser" inManagedObjectContext:_managedObjectContext];
for (id a in selected) {
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"name==%#",a]; //each user has a name attribute
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *array = [_managedObjectContext executeFetchRequest:request error:&error];
//This array is always empty! Why? What am I doing wrong with the request
}
Tell me if you require any more info/further explanation.
Other things to note - there are no warning/error signs - all variables not declared here are declared elsewhere
Thanks a lot!
Since you're not getting any error response, an empty array means that the fetch completed successfully but that it didn't find anything satisfying your predicate. In your code that then implies that selected does not contain values for name that can be found in your data store.
Your code seems to assume that selected is an array of NSStrings which match the name value of some of your stored objects. If that's not the case-- if it contains something other then NSString maybe-- an empty set is to be expected. The fact that a is declared as an id makes me wonder what's really in there.

Core Data filter results for a single attribute and set the text of a UILabel

Baiscally I want to update a UILabel with results of a Core Data query. I have a UILabel with the following text "root has X credits". I want to search Core Data for entity "Account" then refine the search to look for just the "root" account, then refine the search for just the attribute "credit" located in the "root" account. Finally I want update the UILabel to read "root has 0 credits" (or however many credits the Core Data query describes.
So far I have the following code,
- (void)rootCreditAmount {
// Core Data - root credit amount
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// define our table / entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Account" inManagedObjectContext:_managedObjectContext];
[request setEntity:entity];
// filter results to just root user
NSPredicate *username = [NSPredicate predicateWithFormat:#"root"];
[request setPredicate:username];
// fetch records and handle error
NSError *error;
NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:& error] mutableCopy];
if (!mutableFetchResults) {
// handle error.
// should advise user to restart
}
NSLog(#"mutablefetchresults = %#",mutableFetchResults);
}
Needless to say this code is causing my app to crash at the moment.
Change your predicate statement to:
[NSPredicate predicateWithFormat:#"username == root"];
Change "username" to whatever your field name is. See here for more info about formatting predicate strings.
Well thanks to the help of #skytz in chat.stackoverflow.com I was able to do what I needed. I ended up not using NSPredicate. The below method ended up solving my problem. But in the spirit of being a nice guy I'll give the credit to #melsam for the punctionality.
- (void)rootCreditAmount {
// Core Data - root credit amount
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// define our table / entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Account" inManagedObjectContext:_managedObjectContext];
[request setEntity:entity];
// fetch records and handle error
NSError *error;
NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults) {
// handle error.
// should advise user to restart
}
// refine to just root account
for (Account *anAccount in mutableFetchResults) {
if ([anAccount.username isEqualToString:#"root"]) {
NSLog(#"root credit = %#",anAccount.credit);
_lblRootCredit.text = [NSString stringWithFormat:#"root has %# credits.",anAccount.credit];
}
}
}

Resources