Fetching a maximum value with CoreData - objective-c

This is the first time I'm trying to use CoreData and I'm having some trouble getting the max date from a a table.
This is basically what I'm trying to do:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Radar" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"modifiedOn"];
NSExpression *maxDate = [NSExpression expressionForFunction:#"max:" arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:#"maxDate"];
[expressionDescription setExpression:maxDate];
[expressionDescription setExpressionResultType:NSDateAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
NSError *error = nil;
NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
if (objects == nil) {
// Handle the error.
}
else {
if ([objects count] > 0) {
NSLog(#"%d", [objects count]);
NSLog(#"MAx date: %#", [[objects objectAtIndex:0] valueForKey:#"modifiedOn"]);
}
}
This code somehow does the opposite of what I want and print the minimum date. Since I've just started with CoreData it's obvious that I got something wrong, but what?

Maybe you should try to NSLog the [objects lastObject],instead of first one?

Related

to set default value when core data fetch result is null

I am using simple core data fetch request code.
- (NSMutableArray *) read_cd
{
NSError *error = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"List_CD" inManagedObjectContext:cd_Context];
[request setEntity:entity];
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:#"last_date" ascending:NO];
NSArray *sortDescriptor = [[NSArray alloc] initWithObjects:sd, nil];
[request setSortDescriptors:sortDescriptor];
NSMutableArray *mutableFetchResults = [[cd_Context executeFetchRequest:request error:&error] mutableCopy];
if(mutableFetchResults == nil){
//Handle the error
}
return mutableFetchResults;
}
and I'm using return value like this
MSMutableArray *now_cd = self.read_cd;
cell output for {
cell.label1.text = [[now_cd objectAtIndex:i] cd_title];
cell.label2.text = [[now_cd objectAtIndex:i] cd_auth];
}
I want to set default value when executeFetchRequest is null.
so I can continue to use an existing output module.
I don't know how to make a method like that
[[object objectAtIndex:i] instance]

How to Update and Delete the required recored of a table usning Core Data

I am learning the core data
How to delete and update the data using core data. I have worked on upload and fetch. I need to write the methods for delete and update. Please tell me how to update and delete a recode using core data.
Below I have written code for upload and fetch data from table using core data.
-(void)uploadData
{
Employee *empObj=(Employee *)[NSEntityDescription insertNewObjectForEntityForName:#"Employee" inManagedObjectContext:self.managedObjectContext];
empObj.empId=[NSNumber numberWithInt:12345];
empObj.empSalary=[NSNumber numberWithInt:25000];
empObj.empName=#"Venu";
empObj.empDesignation=#"Programmer";
empObj.empExp=#"2 Years";
if ([self.managedObjectContext hasChanges] )
{
[self.managedObjectContext save:nil];
}
}
-(void)fetchData
{
NSEntityDescription *empEntity = [NSEntityDescription entityForName:#"Employee" inManagedObjectContext:self.managedObjectContext];
// Setup the fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSArray *fatherArray=[self.managedObjectContext executeFetchRequest:request error:nil];
[request setEntity:empEntity];
NSArray *empArray=[self.managedObjectContext executeFetchRequest:request error:nil];
for (int i=0; i<[empArray count]; i++)
{
printf("\n=================================Recored== %d==================================== ",i);
Employee *empObj=[empArray objectAtIndex:i];
printf("\n obj.empName========= %s",[empObj.empName UTF8String]);
printf("\n obj.empDesignation========= %s",[empObj.empDesignation UTF8String]);
printf("\n obj.empExp========= %s",[empObj.empExp UTF8String]);
printf("\n obj.empId========= %d",[empObj.empId intValue]);
printf("\n obj.empSalary========= %d",[empObj.empSalary intValue]);
printf("\n============================================================================= ");
}
}
I am doing a project which involved in Core Data, and I would
like to share something with you about it.
It is a clear that before you delete or update a record you need
to retrieve that record.
Use the employee with empId 12345 as an example,
a)Delete
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#:#"Employee"
inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"empId = %d", 12345]];
[request setPredicate:pred];
NSArray *empArray=[self.managedObjectContext executeFetchRequest:request error:nil];
[request release];
if ([empArray count] > 0){
Employee *employee = [empArray objectAtIndex:0];
[self.managedObjectContext deleteObject:employee];
[self.managedObjectContext save:nil];
}
b) update
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#:#"Employee"
inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"empId = %d", 12345]];
[request setPredicate:pred];
NSArray *empArray=[self.managedObjectContext executeFetchRequest:request error:nil];
[request release];
if ([empArray count] > 0){
Employee *employee = [empArray objectAtIndex:0];
employee.empSalary=[NSNumber numberWithInt:45000];
employee.empName=#"John";
employee.empDesignation=#"Analysist";
employee.empExp=#"4 Years";
[self.managedObjectContext save:nil];
}
After a successful fetch-request, you can delete your objects simply by asking the managed objectcontext to delete them:
for (NSManagedObject *managedObject in items) {
[self.managedObjectContext deleteObject:managedObject];
DebugLog(#"%# object deleted",entityDescription);
}
if (![self.managedObjectContext save:&error]) {
DebugLog(#"Error deleting %# - error:%#",entityDescription,error);
}
Updating is done in a similar way, fetch the object desired, change the value, and save the context.

an NSPredicate for selecting a row with maximum value by group

I'm using Core Data to store entities in the form
TrackerEntry
username
timestamp
I want to select the latest record for each user. Using sql it would be something like
SELECT MAX(timestamp) FROM Log GROUP BY username
Is there anyway to create an NSPredicate to do this?
I would do it using NSExpression. This bit of code below won't work for you because you will have to group by username too, but it's a start for the best way of doing this without having to fetch everything. You want to perform the max and group in the db, not in memory - as it will be faster:
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
// Expression for the max
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"timestamp"];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.coreDataStack.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];
NSExpression *valueSumExpression = [NSExpression expressionForFunction:#"max:" arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[[NSExpressionDescription alloc] init] autorelease];
[expressionDescription setName:#"maxTimestamp"];
[expressionDescription setExpression:valueSumExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Filter
//NSPredicate *pred = [NSPredicate predicateWithFormat:#" your predicate here"];
//fetchRequest.predicate = pred;
NSArray *results = [self.coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
if([results count] == 0) {
} else {
// [[results objectAtIndex:0] valueForKey:#"maxTimestamp"];
}
This worked for me, but it is a loop. First you have to get the unique names into an array.
NSFetchRequest *nameRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
nameRequest.entity = entity;
nameRequest.resultType = NSDictionaryResultType;
[nameRequest setPropertiesToFetch:[NSArray arrayWithObject:[[entity propertiesByName] objectForKey:#"name"]]];
NSArray *allNames = [self.managedObjectContext executeFetchRequest:nameRequest error:nil];
names = [allNames valueForKeyPath:#"#distinctUnionOfObjects.name"];
[nameRequest release];
NSLog(#"%#", names);
Not very efficient or convenient. After all, Core Data is not a database but an object graph.
Then you can loop through these and fetch just the top one.
NSMutableArray *mutableResults = [NSMutableArray array];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *numberSort = [NSSortDescriptor sortDescriptorWithKey:#"number" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:numberSort];
request.fetchLimit = 1;
for (NSString *s in names) {
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name = %#", s];
request.predicate = pred;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:nil];
[mutableResults addObject:[results objectAtIndex:0]];
}
[request release];
NSLog(#"%#", mutableResults);

NSSortDescriptor for NSFetchRequest sorting unexpectedly

My entity has a property (sortOrder) that is of the type Decimal(NSDecimalNumber) but when I execute a fetch request using that property as a key, I get back results in a seemingly random order. If I output the value of the property I get really strange values until I get it's intValue.
Example: The first run produces this result. The first value is the raw value of the property. The second is the intValue, the actual value of the property when I created the object - or at least I thought.
85438160 10
74691424 20
Second run...
85333744 10
85339168 20
Third...
85263696 20
85269568 10
What the hell?
Fetch Request:
NSMutableArray *cats = [[NSMutableArray alloc] initWithArray:[CoreDataHelper searchObjectsInContext:#"RestaurantMenuCategory":nil:#"sortOrder":YES:NO:nil]];
Here is the searchObjectsInContext method from my CoreDataHelperClass:
+(NSMutableArray *) searchObjectsInContext: (NSString*)entityName : (NSPredicate *)predicate : (NSString*)sortKey : (BOOL)sortAscending : (BOOL)distinct : (NSString*)distinctProperty
{
RestaurantController *ctrl = [RestaurantController sharedRestaurantController];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:ctrl.managedObjectContext];
[request setEntity:entity];
if(distinct==YES){
[request setReturnsDistinctResults:YES];
}
if(distinctProperty!= nil){
[request setPropertiesToFetch :[NSArray arrayWithObjects:distinctProperty,nil]];
}
if(predicate != nil){
[request setPredicate:predicate];
}
if(sortKey != nil){
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
}
NSError *error;
NSMutableArray *mutableFetchResults = [[[ctrl.managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease];
[request release];
return mutableFetchResults;
}
You cannot use a %d format to print out an NSDecimalNumber.
NSDecimalNumber is an Objective-C object; %d is for printing "int"s. If you use the %d format string, it will probably print something non-useful like the address of the object; use "%#" instead.

Problem with Core Data - EXC_BAD_ACCESS

I'm using the following code and I'm getting an EXC_BAD_ACCESS when trying to get the count of objects - anyone have any idea why? Oddly enough, the error only happens if the count should be one or greater, if there are no objects it seems to work fine (it outputs null).
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"TVShow" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
[fetchRequest includesPendingChanges];
//NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ID == %#", showId];
//[fetchRequest setPredicate:predicate];
NSError *error;
NSLog(#"Generating Count");
NSUInteger count = [[self managedObjectContext] countForFetchRequest:fetchRequest error:&error];
if(count == NSNotFound) {
NSLog(#"error");
}
else {
NSLog(#"%#", count); // EXC_BAD_ACCESS here
}
[fetchRequest release];
Use %d instead of %# in format strings for integers:
NSLog(#"%d", count);
Here's a list of String Format Specifiers.