coredata - fetch one attribute into an array - ios

Aim: I would like to fetch the value of one attribute (from an entity) from the database (core data) into an array.
Example
Entity Name = Employees
Attribute = employeeID
I just want all the employeeIDs populated into an array / set.
Question
Given below is my implementation, I just feel it is kind of a round about way, I would like to know if there is a better way to do this.
Code
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Employees"];
fetchRequest.resultType = NSDictionaryResultType;
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"employeeID", nil]];
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest
error:&error];
NSMutableArray *employeeIDs = [NSMutableArray array];
for(id currentRecord in results)
{
[employeeIDs addObject:[currentRecord objectForKey:#"employeeID"]];
}

You can avoid the last for loop,
Instead of,
NSMutableArray *employeeIDs = [NSMutableArray array];
for(id currentRecord in results)
{
[employeeIDs addObject:[currentRecord objectForKey:#"employeeID"]];
}
Try this,
NSMutableArray *employeeIDs = [results valueForKey:#"employeeID"];

One way of doing it is-
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Employees"];
fetchRequest.resultType = NSDictionaryResultType;
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest
error:&error];
NSMutableArray *employeeIDs = [results valueForKey:#"employeeID"];

Related

Delete record from core data not working?

I am working with core data, when I deleting record from DB it's not working.
Entity name : Entity
Attributes : id, date, title
- (void) getData {
NSFetchRequest * fetReq = [NSFetchRequest fetchRequestWithEntityName:#"Entity"];
NSError * fetchErrorObj;
NSArray *result = [self.ad.managedObjectContext executeFetchRequest:fetReq error:&fetchErrorObj];
NSLog(#"array count is %lu", result.count);
NSMutableArray *idArr = [[NSMutableArray alloc]init];
NSMutableArray *titleArr = [[NSMutableArray alloc]init];
NSMutableArray *dateArr = [[NSMutableArray alloc]init];
for (int i=0; i<result.count; i++) {
self.storedManagedObj = [result objectAtIndex:i];
[idArr addObject:[self.storedManagedObj valueForKey:#"id"]];
[titleArr addObject:[self.storedManagedObj valueForKey:#"title"]];
[dateArr addObject:[self.storedManagedObj valueForKey:#"date"]];
}
self.idArray = sidArr;
}
To delete record...
- (IBAction)deleteRecord:(UIButton *)sender {
NSNumber *value=[NSNumber numberWithInt:[[self.idArray objectAtIndex:0] intValue]];
NSLog(#"%#", [self.idArray objectAtIndex:0]);
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Entity"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", value];
NSLog(#"predicate :%#", predicate);
[request setPredicate:predicate];
NSLog(#"request :%#", request);
NSError *error = nil;
NSArray *result = [self.ad.managedObjectContext executeFetchRequest:request error:&error];
NSLog(#"result: %#", result);
if (!error && result.count > 0) {
for(NSManagedObject *managedObject in result){
NSLog(#"managedObject :%#", managedObject);
[self.ad.managedObjectContext deleteObject:managedObject];
}
//Save context to write to store
[self.ad.managedObjectContext save:nil];
}
}
I am getting result like this
predicate :id == 38
request : (entity: Entity; predicate: (id == 38); sortDescriptors: ((null)); type: NSManagedObjectResultType; )
result :(
)
The error is pretty clear. It states that you need to specify SortDescriptor to your FetchRequest
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Entity"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"<#Sort key#>"
ascending:YES];
request.sortDescriptors = #[sortDescriptor];
OR
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
Read : NSFetchRequest without sort descriptors
EDIT:
As OP isn't concerned about sorting the result in any specific order and the question lacks the description of entity and the only field that I can see in question is id updating my answer to use id in sort descriptor field
[[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
EDIT 2:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Entity"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", [self.idArray objectAtIndex:0]];
Issue in the code was :
NSNumber *value=[NSNumber numberWithInt:[[self.idArray objectAtIndex:0] intValue]];
OP was trying to create a NSNumber from an object in self.idArray using intValue which means idArray is a array of String and not NSNumber. That means id is saved as String in core data and not as NSNumber.
In predicate however OP was trying to pass NSNumber to compare with id. Since id is String and passed argument is NSNumber comparison was failing hence was not returning any objects.

How to get Model class object values while typeCasting it in nsarray?

I typeCast Product(name of a model class where objects is created) class with array (object of NSArray which contains fetched data from database).When I want to set values of project class object into NSMutableDictionary i.e [data setObject:product.prodName forKey:kProductName]; app crashes.
entityDescription = [NSEntityDescription entityForName:#"Product" inManagedObjectContext:appDelegate.managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:#"prodId" ascending:NO];
request.sortDescriptors = #[sd];
[request setPredicate: [NSPredicate predicateWithFormat:#"active = %# AND isDeletedProd = %#",#1,#0]];
_fetchedResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
_fetchedResultController.delegate = self;
request.resultType = NSDictionaryResultType;
NSError *error;
[_fetchedResultController performFetch:&error];
arrdata = [self.fetchedResultController fetchedObjects];
This code i used to fetch data.And then want to typecast it into Product.
Product *arrProd = (Product *)arrdata;
Then Pass arrProd into json by using method given below.
[[ServerSyncUtil sharedInstance] syncProduct:arrProd withHandler:^(BOOL success,NSData *data , NSError *error)
{
}];
Which all this method..
-(void)syncProduct:(Product *)product withHandler:(syncHandler)handler {
NSMutableArray *products = [NSMutableArray array];
[products addObject:[self addProduct:product]];
[self uploadProducts:products withHandler:handler];
}
And then addProduct method called.
-(NSDictionary *) addProduct:(Product *) product {
NSMutableDictionary *data = [NSMutableDictionary dictionary];
NSLog(#"%#",product);
[data setObject:product.prodName forKey:kProductName];
[data setObject:product.desc ? product.desc:#"" forKey:kDescription];
return datal
}
Here when want to setObject into array data app goes crash.
You already have an array, you don't need to create a new one. You're trying to treat an array as a single object. You even call the variable arrdata indicating you know it's an array, but you don't treat it as an array.
Instead use:
NSArray *products = [self.fetchedResultController fetchedObjects];

NSDictionary NSManagedObject

How to convert dictionary data to NSManagedObject data?
I used propertiesToFetch, and it returns dictionary data. But I want NSManagedObject data.
please guide me
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:catalogID, pageID, nil]];
[fetch setResultType:NSDictionaryResultType];
[fetch setReturnsDistinctResults : YES];
NSError* error = nil;
self.resultPageArray = [context executeFetchRequest:fetch error:&error];
When I changed the type to NSManagedObjectResultType, then I got non-distinct data. I read that while using propertiesToFetch it saves the data in dictionary format. But I want to get the distinct data and save it into the NSManagedObjects
Try This,
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:catalogID, pageID, nil]];
[fetch setResultType:NSManagedObjectResultType];
[fetch setReturnsDistinctResults : YES];
NSError* error = nil;
self.resultPageArray = [context executeFetchRequest:fetch error:&error];
My code :
NSError *error = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"BookInfo"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPropertiesToFetch:#[catalogID, pageID]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat:#"(bookId == %#)",strId]];
NSArray *fetchedItems = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if( fetchedItems.count > 0 ) {
BookInfo *bInfo = [fetchedItems lastObject];
NSLog(#"%#",bInfo.bookName);
}
I have solved the issue. I was fetching the data of NSManagedObjects. After that I saved that data to the other array without repetition. And return the new array.
self.resultPageArray = [context executeFetchRequest:fetch error:&error];
NSMutableArray *resultantFinalArr = [[NSMutableArray alloc] init];
for (int i = 0; i<resultPageArray.count; i++)
{
catalogPageDataModel *atIndexI = [resultPageArray objectAtIndex:i];
BOOL find = NO;
for (catalogPageDataModel* catalogPageDataModel in resultantFinalArr)
{
if (catalogPageDataModel.pageid.intValue == atIndexI.pageid.intValue)
{
find = YES;
break;
}
}
if (!find)
[resultantFinalArr addObject:atIndexI];
}
NSLog(#"result array count %lu",(unsigned long)resultantFinalArr.count);
NSLog (#"names: %#",resultantFinalArr);
return resultantFinalArr;

Filter title from core data

I have an entity that has title title and amount. I would like to display the total value I have for each title in my entity.
You can pretty much dispense with fetch requests by leveraging KVC (Key-Value-Coding).
First fetch (or filter) with this predicate:
[NSPredicate predicateWithFormat:#"category = %#", #"Food"];
Then just sum up the result in one line:
NSNumber *sum = [result valueForKeyPath:#"#sum.amount"];
There is no need to fetch only certain attributes using NSDictionaryResultType - just fetch the normal NSManagedObjects (Core Data will optimize for you).
You use NSPredicate to filter your objects by category and then you can fetch only the values of a certain property e.g.:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// Entity
NSEntityDescription *ent = [NSEntityDescription entityForName:#"Incoming" inManagedObjectContext:context];
[request setEntity:ent];
// Predicate
NSPredicate *pred = [NSPredicate predicateWithFormat:#"category MATCHES[cd] %#", #"FOOD"];
[request setPredicate:pred];
// Property fetch
[request setResultType:NSDictionaryResultType];
[request setReturnsDistinctResults:NO];
[request setPropertiesToFetch:#[#"Amount"]];
// Execute the fetch.
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
int total = 0;
if (objects) {
for(NSDictionary *dict in objects) {
NSString *key = dict.allKeys.lastObject;
total += [dict[key] intValue];
}
} else {
NSLog(#"Fetch error: %#", error.localizedDescription);
}
NSLog(#"Total: %i", total);
The following will get the categories and the sum in one fetch operation:
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Incoming"];
fetchRequest.resultType = NSDictionaryResultType;
NSExpression *sumExp = [NSExpression expressionWithFormat:#"sum:(amount)"];
NSExpressionDescription *sumED = [[NSExpressionDescription alloc] init];
sumED.name = #"sum";
sumED.expression = sumExp;
sumED.expressionResultType = NSDoubleAttributeType;
fetchRequest.propertiesToFetch = [#"title", sumED];
fetchRequest.propertiesToGroupBy = [#"title"];
NSArray *dictionaries = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
See the NSExpression documentation here.

Retrieving all the NSSet element values in a one to many relationship

I have a one to many relationship as shown in the attached image. I want to list down all the course titles a particular lecturer teaches and the solution i have come up so far is as follows.
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Lecturer"];
NSMutableSet *courseList = [[NSMutableSet alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == 'smith'"];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *lecturers = [self.managedObjectContext executeFetchRequest:request
error:&error];
for (Lecturer *lecturer in lecturers)
{
NSSet *set = lecturer.courses;
for (Course *course in set)
{
[courseList addObject:course.title];
}
}
The courseList object contains all the courses a given lecturer teaches.
IS there a better way to do this using nspredicates alone and not by using 2 for loops ?
Thanks in advance.
You can just fetch the Course objects directly, but specifying a different predicate that requires their authorname.name to match:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Course"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"authorname.name == 'smith'"];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *courseList = [self.managedObjectContext executeFetchRequest:request error:&error];
If you want an array with just the titles, you can then use:
NSArray *courseTitles = [courseList valueForKeyPath:#"title"];

Resources