I have a 4 Entity One to Many relationship.
Having problem with the fetch and predicates. I am able to fetch the correct 1st entity data (RecordDate) . i use this object self.recordDate. to then fetch the many RecordWorkouts.
my code is below:
self.recordDate = [self.recorddates objectAtIndex:0];
NSLog(#"Date: %#", self.recordDate.date);
NSFetchRequest *fetchWorkoutRequest = [[NSFetchRequest alloc] initWithEntityName:#"RecordWorkout"];
NSPredicate *predicateWorkout = [NSPredicate predicateWithFormat:#"recordDate = %#", self.recordDate];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"recWorkoutName" ascending:YES];
[fetchWorkoutRequest setSortDescriptors:#[sortDescriptor]];
[fetchWorkoutRequest setPredicate:predicateWorkout];
self.recordworkouts = [[managedObjectContext executeFetchRequest:fetchWorkoutRequest error:nil] mutableCopy];
self.recordWorkout = [self.recordworkouts objectAtIndex:0];
NSLog(#"Workout: %#", self.recordWorkout.recWorkoutName);
I manage to fetch the RecordWorkout associated with the RecordDate Entity. This works fine for when there is only one object stored in RecordWorkout.
But When there is more than one stored in RecordWorkout It will fetch them all.
Is it possible to add a secondary NSPredicate within this fetch to for example only fetch the recordWorkout that is equal to workoutLabel.text.
Thanks
Answer for anyone who may need it.
Within Predicate you can have two requests:
NSPredicate *predicateWorkout = [NSPredicate predicateWithFormat:#"recordDate = %# AND recWorkoutName == %#", self.recordDate, testLabel2.text];
Related
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.
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.
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
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
I am wanting to set up a basic relationship with two entities in Core Data, but the relationship is either not saving, or is not working properly and I'm not sure why.
The two entities are Character and Avatar, its a one-to-one relationship. A character can have 1 avatar. Technically, it should be a "one avatar can be owned by many characters", but I'll deal with that later.
I want to add characters and assign them an avatar.
There are already 10 avatars in Core Data and 1 character, both of which I've verified via the Terminal and SQLite.
The problem is, I'm having troubling "finding an avatar by a name and then saving the relationship to a character".
So far,
I set up a fetch request called: "frqAvatarWithName" where the Predicate has the following structure:
[quote]
name == $AVATAR_NAME
[/quote]
This is so: I can find an avatar with a certain name; and then I can create a relationship with a character.
Issue 1: It gets to execute the query but then never displays how many records there are.
I get a EXC_BAD_ACCESS error in debug mode and I have traced it back to the fetch request template handling -- so, this must be in error or I have done it wrong.
Issue 2: I am not sure if I am even setting up this "basic" relationship up properly.
[code]
// This code is meant to find an avatar with a certain name and then save the relationship
// between a character and said avatar.
// This is my app delegate file for the moment
// All the files are present, and I have deleted/recreated the app various times
-(void)characterMaker
{
NSLog(#"Inside characterMaker...");
NSError *error = nil;
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObjectModel *model = [self managedObjectModel];
// Find an avatar with a specific name
NSString *nameToFind = #"avt_player_1";
// Use a Fetch request template
NSDictionary *subs = [NSDictionary dictionaryWithObjectsAndKeys:nameToFind, #"AVATAR_NAME", nil];
NSFetchRequest *fetchRequest = [model fetchRequestFromTemplateWithName:#"frqAvatarWithName"
substitutionVariables:subs];
// Set the entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Avatar"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Execute the query (it never even reaches this point)
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// Handle the error
NSLog(#"Error -- %#", [error localizedDescription]);
abort();
}
NSLog(#"Found %# records", [fetchedObjects count]);
// Print out avatar names
for (Avatar *a in fetchedObjects)
{
NSLog(#"Name = %#", [a valueForKey:#"name"]);
}
// This is where I would use `a` and store it in a character entity, and thus create the relationship
[/code]
I gave up on this and did the whole project with the FMDatabase project and SQLite; I've been able to resolve the problem this way.
Thread closed.