Core Data: NSPredicate with managed objects - objective-c

I am creating an iOS 5 app using Core Data.
I have two entities Item and Category there is a many-to-many relationship between these two entities, i.e. an Item belongs to many categories and a Category has many items.
What I am trying to do is, given a category, I want to know all the categories the items of that category is associated with. For that I am trying to execute the following request:
NSEntityDescription *catEntity = [NSEntityDescription entityForName:#"Category" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = catEntity;
request.predicate = [NSPredicate predicateWithFormat:#"items IN %#",[category.items allObjects]];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]];
NSError *error = nil;
NSArray *categories = [context executeFetchRequest:request error:&error];
But when executing this I get the following error:
'NSInvalidArgumentException', reason: 'unimplemented SQL generation for predicate : (items IN {<Item: 0x89b9c50> (entity: Item; id: 0x89be960 <x-coredata://A5DE0832-95F1-460C-9F40-202A10E16BDC/Item/p17> ; data: {
attributes = (
);
categories = (
"0x89be540 <x-coredata://A5DE0832-95F1-460C-9F40-202A10E16BDC/Category/p28>",
"0x89be680 <x-coredata://A5DE0832-95F1-460C-9F40-202A10E16BDC/Category/p29>"
);
name = "Some Item";
})})'
What am I doing wrong here?

Try this, I'm not sure but it might work:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY items IN %#", [category.items allObjects]];

Related

Core data delete single record from to many relation ship

I have created 4 entities.
User, Mobile, Email, Address.
User have to many relationship (name as numbers) with Mobile.
I have subclass for all of above. How to delete single mobile number from particular user? How to update single mobile number from particular user?,what Predicate use for that?
code is here:
NSManagedObjectContext *context = [self managedObjectContext]; NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:NSStringFromClass([User class])];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY numbers.number == %#",self.textField.text];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *array = [context executeFetchRequest:request error:&error]; Mobile *objMobile;
User *objUser;
objUser = [array objectAtIndex:0];
for (User *obj in [objUser.numbers valueForKey:#"number"]) {
NSLog(#"%#",obj);
NSString *str1 = [NSString stringWithFormat:#"%#",obj];
NSString *str2 = [NSString stringWithFormat:#"%#",self.textDelete.text];
if ([str1 isEqualToString:str2] ) {
[objUser removeNumbersObject:objMobile]; }
}
NSLog(#"%#",[objUser.numbers valueForKey:#"number"]); self.textAddUserDetail.text = #"";
if (![context save:&error]) { }
Basically, don't search based on the user and the relationship. Instead, search directly for the number and then delete it or edit it:
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:NSStringFromClass([Number class])];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"number == %#", self.textField.text];
Then you also don't need a loop and extra consideration of what to do.
It will be useful to use "Magical Records" Library.it work with Key value coding need not to maintain Relationships.it will Automatically get the unique Key From all the Entitys

Core Data NSFetchRequest within specific object using NSPredicate

I have a core data entity, "Entity 1" it has a one to many relationship lets call it "entityRelationship" to another entity "Entity 2".
I'd like to be able to perform a NSFetchRequest for use with a NSFetchResultsController to return the list of "Entity 2" objects for a specific "Entity 1" object.
I have the "Entity 1" stored out as it's own variable, but i can't seem to find the correct way to set up an NSPredicate to return the objects:
Here's my code:
NSFetchedResultsController *fetchedEvents;
NSFetchRequest *fetchRequest;
NSError *error = nil;
fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Entity2"];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"Entity2 IN self = %#",entity1Object]];
[fetchRequest setSortDescriptors:#[]];// no sort descriptors
fetchedEvents = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:theManagedObjectContext sectionNameKeyPath:nil cacheName:nil];
[fetchedEvents performFetch:&error];
if (error) {
NSLog(#"Unable to perform fetch.");
NSLog(#"%#, %#", error, error.localizedDescription);
}
return fetchedEvents;
This crashes with the following error:
** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "NSMDEvents IN self = %#"'
Am i doing something wrong? Or is this the incorrect way to go about returning entities with relationships?
Since you have entity1Object and the defined relationship, you can retrieve the Entity2 objects directly from there
NSSet *entity2Objects = [entity1Object valueForKey:#"entityRelationship"];
An extra fetch is not needed.
But if you really need the fetch define a reverse relationship and use a property with an unique value.
For example let's assume that entity1 are clubs and entity2 are their members and you want to get all members for a specific club use this predicate:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Member"];
[NSPredicate predicateWithFormat:#"club.name == %#", currentClub.name];
The literal club in the predicate is the reverse relationship object.
Or translated to your example
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Entity2"];
[NSPredicate predicateWithFormat:#"entity1.property == %#", entity1Object.property];
Trying the suggested code (thanks vadian) kept causing my app to crash with various errors regarding keys not existing etc, this turned out to be down to a relationship issue.
"Entity2" was inheriting from another entity (had its parent Entity field set in the Data Model Inspector)"Entity 0". However the relationship between "Entity1" was between itself and "Entity0" not "Entity2".
So after a rejig of the core data model "Entity2" had a relationship added (lets call it "EntityEvents") between itself and "Entity1". Now using the following code i was able to select the specific events from the current object:
NSFetchedResultsController *fetchedEvents;
NSFetchRequest *fetchRequest;
NSError *error = nil;
fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Entity2"];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"EntityEvents == %#",Entity1]];
[fetchRequest setSortDescriptors:#[]];// no sort descriptors
fetchedEvents = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:theManagedObjectContext sectionNameKeyPath:nil cacheName:nil];
[fetchedEvents performFetch:&error];
if (error) {
NSLog(#"Unable to perform fetch.");
NSLog(#"%#, %#", error, error.localizedDescription);
}
return fetchedEvents;

Searching CoreData relationships

I'm about to pull my hair out trying to figure out why this isn't working.
I have two entities:
Quote
Customer
A Quote has a one-to-one relationship property with a Customer called simply 'customer'. The Customer has a CoreData objectID (obviously). I am trying to search through all the Quote's and return the one's that have a specific Customer associated with it based off the Customer objectID. Reading through all the tutorials I've managed to get this but I keep getting a crash:
+ (void)fetchQuotesForCustomerID:(NSManagedObjectID*)objectID results:(void(^)(NSError* error, NSArray *fetchedResults))completion {
NSManagedObjectContext *context = [[QuoteGenerator sharedGenerator] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Quote"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"customer.objectID == %#", objectID];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(#"fetch error = %#", [error localizedDescription]);
completion(error, nil);
} else {
NSLog(#"fetch count = %d", fetchedObjects.count);
completion(nil, fetchedObjects);
}
}
Output error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath customer.objectID not found in entity <NSSQLEntity Quote id=13>'
Is the predicated setup wrong? Reading through the documentation is says that you can use dot syntax to access properties in the predicate.
Please help...
Turns out a lack of sleep and #Gary lead me to the right answer.
I should have had a to-many relationship from customer to Quote.
When comparing an entities NSManagedObjectID property you don't have to explicitly state it. So the following modification to the NSPredicate fixed my issue.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY
customer == %#", objectID];
You shouldn't need to do a fetch at all, core data should generate a quotes member on your customer object that will return an NSSet of all the related quote objects.

Core Data Issue - Unable to store NSNumber

I am trying to use Core Data in my application. I want to store an attribute "totalKM".
to store my attribute I use these lines:
Model *event = (Model *)[NSEntityDescription insertNewObjectForEntityForName:#"Model" inManagedObjectContext:managedObjectContext];
int number = 4;
[event setTotalKM:[NSNumber numberWithDouble:number]];
to read my attribute I use these:
Model *event = (Model *)[NSEntityDescription insertNewObjectForEntityForName:#"Model" inManagedObjectContext:managedObjectContext];
NSNumber *number = [event totalKM];
My attribute "totalKM" is always default value, O. And I have no exception. Am i missing something?
Thanks.
insertNewObjectForEntityForNamethis method use to put model to context.
this is a new object.
the right way is:
Set new one
Model *event = (Model *)[NSEntityDescription insertNewObjectForEntityForName:#"Model" inManagedObjectContext:managedObjectContext];
int number = 4;
[event setTotalKM:[NSNumber numberWithDouble:number]];
//save change if need
NSError *error = nil;
if (![self.manageObjectContext save:&error]) {
NIDERROR(#"save managedContext error :%#",error);
}
fetch object progress
When you need to get a model form coredate.u need 2 fetch use fetch
like this dome
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Board"
inManagedObjectContext:self.manageObjectContext]];
//set fetch conditions
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"board_id == %#", aBoardID];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *results = [self.manageObjectContext executeFetchRequest:fetchRequest error:&error];
if (error) {
NIDERROR(#"fetch board error.\n board id: %# \n error:%#", aBoardID, error);
return nil;
}
Model *model = results[0];
NSLog(#"%#",model.totalKM)

CoreData Fetching Results With 3 Entities and Many to Many Relationships

I have a DataModel that has a Category, SubCategory, and DetailedItem entities. Category has a 1-to-many to the SubCategory. Each SubCategory has a 1-to-many relationship to DetailedItem. So a Category has a Set of subCategories and for each SubCategory it has a Set of detailedItems.
Category has a Set property of subCategories, and a Name property.
SubCategory has a Set property of detailedItems, a Name Property, and Category parent property
My question is how can I use NSFetchedResultsController to retrieve all the detailedItems from a given SubCategory in a given Category.
I'm trying something like this but I think my NSPredicate is incorrect
if (__fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"DetailedItem" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Category.name CONTAINS[c] 'Movies'"];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES]; // probably not needed
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSFetchedResultsController *fetchedResults = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:#"AllItems"];
fetchedResults.delegate = self;
__fetchedResultsController = fetchedResults;
NSError *error;
if (![__fetchedResultsController performFetch:&error]) {
NSLog(#"Error fetching");
}
[sortDescriptor release];
[fetchRequest release];
}
The Goal being if Category == Food and SubCategory == Meat, then i'm getting a list of all detailedItems that fall under that Category & SubCategory. If anything isn't clear I'll try to provide more context.
If your datamodel looks like:
Category{
name:string
subCategories<-->>SubCategory.category
}
SubCategory{
name:string
category<<-->Category.subCategories
detailedItems<-->>DetailItem.subCategory
}
DetailedItem{
name:string
subCategory<<-->SubCategory.detailedItems
}
... and you want a table of DetailedItem objects, you set the fetch entity to DetailedItem and then you have all your keypaths begin from the DetailItem entity.
If you just have the names of the Category and SubCategory objects then you could connstruct a predicate like:
NSPredicate *p = [NSPredicate predicateWithFormat:#"subCategory.name==%# AND subCategory.category.name==%#", subCatName,catName];
Note that if you have duplicate name values in either entity's objects, you will get all matching objects.
If you have the actual Category and SubCategory objects in hand you can do a faster test with:
NSPredicate *p = [NSPredicate predicateWithFormat:#"subCategory==%# AND subCategory.category==%#", aSubCatObj,aCatObj];