Retrieve Fetch Request from Managed Object Context - core-data

I created a Fetch Request "MyRequest" in the visual editor for my Core Data Model (where you also can visually add Entities as well). Now that the fetch request is created, how can I retrieve the fetch request from the model so I can execute it?
In pseudo code, I'd like to do something like this:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithName:#"MyRequest" inManagedObjectContext:myManagedObjectContext];
NSArray *fetchedObjects = [myManagedObjectContext executeFetchRequest:request error:nil];
Thanks!

NSFetchRequest *fetchRequest = [self.managedObjectModel􏰁 fetchRequestTemplateForName:#"MyRequest"];

Related

How to sort Core Data results based on an attribute of related object collection?

Setup: I have a collection of parent objects, call them ObjectA. Each ObjectA has a one-to-many relation to ObjectB. So, one ObjectA may contain 0..n ObjectB-s, and each ObjectB has a specific ObjectA as its parent.
Now, I would like to do a Core Data fetch of ObjectA-s, where they are sorted by their latest ObjectB. Is it possible to create a sort descriptor for that?
There is a related question that describes exactly the same situation. The answer suggests denormalizing the attribute from ObjectB into ObjectA. This would be OK if there really is no way to do this with one fetch request.
The related question also mentions:
Actually, I just had an idea! Maybe I can sort Conversations by messages.#max.sortedDate…
I tried. It doesn’t seem to be possible. I get this error:
2012-10-05 17:51:42.813 xxx[6398:c07] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: 'Keypath containing
KVC aggregate where there shouldn't be one; failed to handle
ObjectB.#max.creationTime'
Is denormalizing the attribute into ObjectA the only/best solution?
You could add an attribute in ObjectB which is the time stamp of the add date, then in the fetch request you can do something like this:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"objectB.addTime" ascending:YES];
...
fetchRequest.sortDescriptors = #[descriptor];
I know this question is a bit old but what I did was get all ObjectBs, iterate over the results and pull out the ObjectB property and add it to a new array.
NSFetchRequest *fetchRequest = [NSFetchRequest new];
[fetchRequest setEntity:self.entityDescForObjectB];
// sort
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
[fetchRequest setSortDescriptors:#[sortDescriptor]];
NSError *error = nil;
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"Error fetching objects: %#", error.localizedDescription);
return;
}
// pull out all the ObjectA objects
NSMutableArray *tmp = [#[] mutableCopy];
for (ObjectB *obj in fetchedObjects) {
if ([tmp containsObject:obj.objectA]) {
continue;
}
[tmp addObject:obj.objectA];
}
This works because CoreData is an object graph so you can work backwards. The loop at the end basically checks to see if the tmp array already has a specific ObjectA instance and if not adds it to the array.
It's important that you sort the ObjectBs otherwise this exercise is pointless.

CoreData Fetch Predicate for unrelated entities

I am having trouble to do a CoreData fetch request for unrelated entities. Lets assume I have an object model with 3 entities: Message, User and Advisor.
I want this 3 objects to be unrelated to each other. So a Message does have an attribute senderEmail and receiverEmail whilst User and Advisor do have the attribute email.
But again, there is no further relationship between those objects.
I now want for example to fetch the latest (newst) Message by an advisor or by a user. But how should I do this fetch predicate since the objects are not connected?
Is this even possible within one Fetch Request or do I need to fetch each objects separately into an array and then make further operations to get what I want?
Alexander,
if those entities are not related each other you need to excecute different fetch requests to grab your data.
So, for example, you could grab the latest Message setting up a request like the following:
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"senderEmail == %#", grabbedEmail];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"insertionDate" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSFetchRequest *messageFetch = [[NSFetchRequest alloc] init];
[messageFetch setEntity:[NSEntityDescription entityForName:#"Message" inManagedObjectContext:yourContext]];
[messageFetch setPredicate:predicate];
[messageFetch setSortDescriptors:sortDescriptors];
[messageFetch setFetchLimit:1];
To retrieve the grabbedEmail (if you don't have it) you need to set up a request with a specific predicate. The same could be applied for the receiver email. For example.
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"userId == %#", #"someUserId"];
NSFetchRequest* userFetch = [[NSFetchRequest alloc] init];
[userFetch setEntity:[NSEntityDescription entityForName:#"User" inManagedObjectContext:yourContext]];
[userFetch setPredicate:predicate];
[userFetch setFetchLimit:1];
NSArray* userResults = [userFetch executeFetchRequest:&error];
User* retrievedUser = (User*)[userResults objectAtIndex:0];
NSString* grabbedEmail = [retrievedUser email];
To sort by date you could simply add to Message enitity an attribute called insertionDate (of type NSDate) that allows you to order by date.
When you execute the request
NSArray* results = [messageFetch executeFetchRequest:&error];
the array results will contain the (only) Message element you are looking for.
Why do you need to maintain separate those entities?
Hope that helps.

Filtering with NSPredicate in one-to-many relationships

I tried a lot of the solutions in stackoverflow but I'm not able to find a valid one. I have a core data model with two entities: Client and Destination. Both are wrapped by NSManagedObjectsubclasses.
Client has some properties and a one-to-many relationship called destinations.
Destination has a property called default_dest that is wrapped by a NSNumber and an inverse relationship called client.
I have a UITableViewController where I'm using the following fetchedController property. The request works well. I'm able to retrieve clients stored in SQLite.
if (fetchedResultsController)
return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Client" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"code" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = self;
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
I would make another step. I would now filter the destinations retrieved from the previous request (that are contained in destinations NSSet) for each client. In particular, the destination can be added only if its default_dest value is 1.
To fix this specification I tried to add an NSPredicate like the following:
NSPredicate* predicate = [NSpredicate predicateWithFormat:#"ANY destinations.default_dest == %#", [NSNumber numberWithInt:1]];
Then I set it in fetchRequest as:
[fetchRequest setPredicate:predicate];
Each time I run the request, it returns a "to-many-relationship fault destinations...". What does it mean?
I've read iphone-core-data-relationship-fault but I don't understand what does it mean.
So, my questions are: Is it possible to reach a similar goal? If yes, do you have any suggestions?
Notes
Obviously I could iterate over destinations set but I don't know if could be an expensive iteration and how many records there are.
For those interested in.
You need to say to your fetch request to prefetch relationships using
- (void)setRelationshipKeyPathsForPrefetching:(NSArray *)keys
For example:
[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects: #"destinations", nil]];
In this manner Core Data prefetch the relationships you have specified and doesn't fire fault.
In addition you can limit the number of results for your fetch request by limiting it using:
- (void)setFetchLimit:(NSUInteger)limit
Hope it helps.
Here is a different way to retrieve specific values in fetch. Maybe this can help (look up link name in document):
Fetching Specific Values

Count entity in Core Data with a specific Value

I have an Entity with some Attribute. I have my tabes already populates(SQLite table)
In one Attribute (i'll call Attribute1) i have a bool value, changing during use of my app.
How can i return the count of my Entities with Attribute1 value YES?
I've already read "Core data Tutorial" and "Predicate Programing Guide" but i don't understand how to proceed..
NSPredicate *predicate= [NSPredicate predicateWithFormat:#"Attribute1 == %#",[NSNumber numberWithBool:YES]];
I've tried with this, and then? it seems not working..
The best bet is to use the countForFetchRequest method. Set up your predicate and fetch request, but instead of doing the actual fetch, execute countForFetchRequest as follows:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"Attribute1 == %#",
[NSNumber numberWithBool:YES]];
[request setPredicate:predicate];
NSUInteger count = [myManagedObjectContext countForFetchRequest:request error:nil];
You can find more info in the Apple API Docs:
countForFetchRequest:error:
Returns the number of objects a given fetch request would have returned if it had been passed to executeFetchRequest:error:.
(NSUInteger)countForFetchRequest:(NSFetchRequest )request error:(NSError *)error
Parameters
request
A fetch request that specifies the search criteria for the fetch.
error
If there is a problem executing the fetch, upon return contains an instance of NSError that describes the problem.
Return Value
The number of objects a given fetch request would have returned if it had been passed to executeFetchRequest:error:, or NSNotFound if an error occurs.
Availability
Available in iOS 3.0 and later.
Declared In
NSManagedObjectContext.h

How to serialize a NSPredicate object?

Is there a way to inspect a NSPredicate object for the purposes of serializing it into a URL? I am trying to retrieve the data remotely and need to translate the predicate object into a URL with querystring parameters that the server understands.
This was inspired by a talk given in WWDC 2010 called "Building a Server Driven User EXperience" where the speakers talk about using Core-Data and with a server backend. I have followed the session video and slides, but am stuck on the serializing point. For example, there is a Person object, and I'm trying to fetch all people whose first name is "John". I am using a subclass of NSManagedObjectContext called RemoteManagedObjectContext, which overrides the executeFetchRequest method, and is supposed to send the call to the server instead. The fetch request is being created as (ellipsed non-essential parts):
#implementation PeopleViewController
- (NSArray *)getPeople {
RemoteFetchRequest *fetchRequest = [[RemoteFetchRequest alloc] init];
NSEntityDescription *entity = ...
NSPredicate *template = [NSPredicate predicateWithFormat:
#"name == $NAME AND endpoint = $ENDPOINT"];
NSPredicate *predicate = [template predicateWithSubstitutionVariables:...];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
// the custom subclass of NSManagedObjectContext executes this
return [remoteMOC executeFetchRequest:fetchRequest error:&error];
}
#end
Now inside the custom subclass of NSManagedObjectContext, how can I serialize the fetch request into querystring parameters suitable for the server. So given the above fetch request, the corresponding URL would be:
http://example.com/people?name=John
It is possible to get a string representation of the predicate which returns,
name == "John" AND endpoint == "people"
that I can parse to get the parameters name, and endpoint. However, is it possible to do it without parsing the string? Here's a partial implementation of the RemoteManagedObjectContext class.
#implementation RemoteManagedObjectContext
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error {
// this gives name == "John" AND endpoint == "people"
// don't know how else to retrieve the predicate data
NSLog(#"%#", [[request predicate] predicateFormat]);
...
}
#end
Even better than a string representation is an object-oriented representation! And it's done automatically!
First, check the class of the NSPredicate. It will be an NSCompoundPredicate. Cast it to an appropriate variable.
You'll then see that it's compoundPredicateType is NSAndPredicateType, just like you'd expect.
You can also see that the array returned by -subpredicates reveals 2 NSComparisonPredicates.
The first subpredicate has a left expression of type NSKeyPathExpressionType and a -keyPath of #"name", the operator is NSEqualToPredicateOperatorType. The right expression will be an NSExpression of type NSConstantValueExpressionType, and the -constantValue will be #"John".
The second subpredicate will be similar, except that the left expression's keyPath will be #"endpoint", and the right expression's constantValue will be #"people".
If you want more in-depth information on turning NSPredicates into an HTTP Get request, check out my StackOverflow framework, "StackKit", which does just that. It's basically a framework that behaves similarly to CoreData, but uses StackOverflow.com (or any other stack exchange site) to retrieve information. Underneath, it's doing a lot to convert NSPredicate objects into a URL. You're also welcome to email me any specific questions you have.

Resources