coredata-deleting from database and making request - sql

Hi I am a bit noob whit core-data so I request for your answer, I can pull out data from database whit this functions:
NSManagedObject *selectedObject = [[self fetchedResultsController]
objectAtIndexPath:indexPath];
[[selectedObject valueForKey:#"SOMECOLLUMNNAME"] description];
But I have a really big problems whit deleting from database I have read that I should use NSPredicate I read the tutorial but I do no figure out how can I write a simple
DELETE *
FROM Table t
WHERE t.date == 01.01.2011
for example.
Can You Help me pls

Hmm. I assume the date object is a NSString, not a NSDate.
Try this:
...// your code
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"date == %#", #"01.01.2011"];
[request setPredicate:predicate];
// Execute the fetch -- create a mutable copy of the result.
NSError * error = nil;
NSMutableArray * mutableFetchResults = [[yourManagedObjectContext executeFetchRequest:request error:&error] mutableCopy];
for (int i = 0; i < [mutableFetchResults count]; i++)
{
YourEntity * object = (YourEntity*)[mutableFetchResults objectAtIndex:i];
[yourManagedObjectContext deleteObject:object];
}
[mutableFetchResults release];
Pls ask if you need more help.

Thanks a lot Elias
Here is my nearly final code:
-(void)deleteLastDate{
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:0];
NSString *startDate=[[NSString alloc]initWithString:#"01.01.2011"];//[[managedObject valueForKey:#"date"] description]];
NSManagedObjectContext *moc = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(date == %#)", startDate];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:[entity name] inManagedObjectContext:moc]];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];
int aegedInt = [results count];
for (int i = 0; i<aegedInt; i++) {
[moc deleteObject:[results objectAtIndex:i]];
}
}
I hope it will help people dealing whit same problem
Thanks again Elias

Related

Saving data in background thread doesn't work

I am trying to save my data in CoreData in background thread, but it crash or it doesnt work, any idea where am I doing the mistake?
When I try with main thread it works correctly, I tried to google to find some information in background thread, I couldn't find some useful article about it.
any help appreciate.
Thanks
This is the objective -c code, what I tried
-(void)insertNameAndSurnameInDataBase:(NSString *)name surname:(NSString *)surname numbers:(NSArray *)numbers labels:(NSArray *)labels{
NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[backgroundMOC performBlock:^{
NSError *error;
NameAndSurname *nameAndSurname = [NSEntityDescription insertNewObjectForEntityForName:#"NameAndSurname" inManagedObjectContext:backgroundMOC];
NSString *nSurname = [NSString stringWithFormat:#"%# %#",name,surname];
nameAndSurname.nameSurname = nSurname;
if ([backgroundMOC save:&error]) {
}
else{
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"NameAndSurname"
inManagedObjectContext:backgroundMOC];
// predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"nameSurname =[c] %#", nSurname];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSArray *fetchedObjects = [backgroundMOC executeFetchRequest:fetchRequest error:&error];
if([fetchedObjects count] > 0){
[numbers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
id obj2 = [labels objectAtIndex:idx];
obj = [obj stringByReplacingOccurrencesOfString:#" " withString:#""];
ContactNumber *phoneNumber = [NSEntityDescription insertNewObjectForEntityForName:#"ContactNumber" inManagedObjectContext:backgroundMOC];
phoneNumber.number = obj;
phoneNumber.label = obj2;
phoneNumber.nameAndSurname = fetchedObjects[0];
NSError *error;
if ([backgroundMOC save:&error]) {
}
else{
}
}];
}
}];
}

Random function in Core Data Xcode

Im a new programmer trying to make a random function using Core Data. What I want is for the label to return a random managedObject from my entity. Here is my code
- (IBAction)randomize{
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:#"Restraunt" inManagedObjectContext:context ];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSError *error;
NSArray *matchingData = [context executeFetchRequest:request error:&error];
NSString *textString;
int RandomNumber;
RandomNumber = arc4random() %[matchingData count];
textString = [matchingData objectAtIndex:RandomNumber];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"restraunt_name like %#",textString];
[request setPredicate:predicate];
if(matchingData.count <= 0){
self.label.text = #"doesnt exist";}
else {
NSString *string;
for (NSString *obj in matchingData){
string = [obj valueForKey:#"restraunt_name"];
}
self.label.text = [NSString stringWithFormat:#" %#", string] ;
}
}
There are several things wrong in this code. For instance, "textString" is not a string, it's one of your Restraunt entities. Also, the for loop you have in the else clause just loops through all you entities (making your random selection irrelevant), so "string" will be the last restaurant name in your data. Your code should look something like this,
- (IBAction)randomize{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Restraunt"];
NSError *error;
NSArray *matchingData = [context executeFetchRequest:request error:&error];
int randomNumber = arc4random() %[matchingData count];
NSManagedObject *aRestraunt = matchingData[randomNumber]; // aRestraunt might not be an NSManagedObject depending on whether you've subclassed NSManagedObject or not -- if you have, then that should probably be Restraunt instead.
self.label.text = [aRestaurant valueForKey:#"restraunt_name"];
}
After Edit:
The answer I provided above was basically a "fix up" of your code to make it work. However, it's not the most efficient way to get a single random object. There's no need to fetch all the objects into memory just to get one. Instead you can get the count of your records as Hal Mueller suggested in his comment, then use the fetchOffset in combination with the fetchLimit to get one record,
NSError *error;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Restraunt"];
NSUInteger count = [context countForFetchRequest:request error:&error];
if (! error) {
NSUInteger rand = arc4random_uniform() % count;
[request setFetchOffset:rand];
[request setFetchLimit:1];
NSError *fetchError;
NSManagedObject *aRestraunt = [[context executeFetchRequest:request error:&fetchError] lastObject];
if (! fetchError) {
self.label.text = [aRestaurant valueForKey:#"restraunt_name"];
}else{
NSLog(#"There was an error in fetching a Restraunt entity");
}

Recipes to update database in Core Data

I have a method for adding stamp to the card, from QR code reader to web service
my question is,
Here is my code:
- (void)addStamp
{
NSString *url = [_URL stringByAppendingString:#"add-stamp"];
NSString *post = [NSString stringWithFormat:#"userId=%#&code=%#", self.userId, self.code ];
post = [post stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *postData = [NSData dataWithBytes:[post UTF8String]
length:[post lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL
URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:600];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
}
Rightnow I want to update my DB with new method -> if the code is repeated add stamp, if not create add a new card:
-(void)addStampInDB:(int)cardId
{
NSManagedObjectContext* managedObjectContext = [(AppDelegate*) [[UIApplication
sharedApplication] delegate] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Card"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"remote_id = %d", cardId];
[fetchRequest setPredicate:predicate];
[managedObjectContext lock];
NSError *error;
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest
error:&error];
[managedObjectContext unlock];
Card *d = nil;
if([fetchedObjects count] > 0 ){
d = [fetchedObjects objectAtIndex:0];
cardId++;
} else{
d = [NSEntityDescription insertNewObjectForEntityForName:#"Card"
inManagedObjectContext:managedObjectContext];
}
NSArray *test;
for(NSDictionary *stamp in test)
{
d.remote_id = [NSNumber numberWithInt:[[stamp objectForKey:#"id"] intValue]];
d.stampNumber = [NSNumber numberWithInt:[[stamp objectForKey:#"stampNumber"] intValue]];
d.createdAt = [NSDate dateWithTimeIntervalSince1970:[[stamp objectForKey:#"createdAt"]
intValue]];
[managedObjectContext lock];
NSError *error;
if (![managedObjectContext save:&error])
{
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
} else {
NSLog(#" %#", [error userInfo]);
}
}
[managedObjectContext unlock];
}
}
I don't know if I'm in a right way or not and also how I can test my method?
I'm not very sure about your question but I'll try to give some hints.
First
Card *d = nil;
if([fetchedObjects count] > 0 ){
d = [fetchedObjects objectAtIndex:0];
cardId++;
} else{
d = [NSEntityDescription insertNewObjectForEntityForName:#"Card"
inManagedObjectContext:managedObjectContext];
}
Here you have found an existing card, you use it, else you create a new. Question: what about cardId? Where is it used?
Second
for(NSDictionary *stamp in test)
{
d.remote_id = [NSNumber numberWithInt:[[stamp objectForKey:#"id"] intValue]];
d.stampNumber = [NSNumber numberWithInt:[[stamp objectForKey:#"stampNumber"] intValue]];
d.createdAt = [NSDate dateWithTimeIntervalSince1970:[[stamp objectForKey:#"createdAt"]
intValue]];
// other code here
}
If you loop test, you overwrite the value of your card d each time. Is it right?
Third
for(NSDictionary *stamp in test)
{
// other code here
}
// save here
Move the save out of the for loop. This boost performances in your app. It is not necessary to save each time in your loop. Do it at the end only.
Hope that helps.
P.S. If you want to know something else let me know.

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.

NSLog and Core Data

I have three Classes for which I am extending NSManagedObject (I know this isn't required but I wanted the property notation). Theses Classes are QuestionSet, Question and Answer. My data model is setup so that there's a many to many between them like so: QuestionSet <<->> Question <<->> Answer. I load up everything from a server and it save successfully meaning I look in the .db file and it's all how I expect, if I immediately NSLog the array questionsets they look great and if I go take a quiz it works great.
However if I NSLog that array anywhere but right after where I load them from the server, it crashes my app. The quiz still runs fine so I know the data is in there and in the expected format. Does this have something to do with Core Data clearing out space and then my relationships don't 'lazy loaded' when I'm just trying to log them? Sorry, still wrapping my head around core data.
This bit works, I load from the server and at the bottom I 'loadTrivia' and log what I get. The issue comes if at sometime later during the course of the app execution, an NSLog of the questionsets will fail.
- (void)loadQuestionSetFromNetworkWithID:(NSNumber *)p_id andTitle:(NSString *)p_title
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:kTriviaQuestionSetURL, [p_id intValue]]]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *questions = [[[sbjson objectWithString:json_string error:nil] valueForKeyPath:#"Q"] objectAtIndex:0];
NSError *error;
NSFetchRequest *questionsetRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *questionsetEntity = [NSEntityDescription entityForName:#"QuestionSet" inManagedObjectContext:[self managedObjectContext]];
NSPredicate *questionsetPredicate = [NSPredicate predicateWithFormat:#"id = %d", [p_id intValue]];
[questionsetRequest setEntity:questionsetEntity];
[questionsetRequest setPredicate:questionsetPredicate];
QuestionSet *qs = nil;
NSArray *questionSetObjects = [[self managedObjectContext] executeFetchRequest:questionsetRequest error:&error];
if (questionSetObjects == nil){
// Handle errors
}
if ([questionSetObjects count] > 0)
qs = [questionSetObjects objectAtIndex:0];
else
qs = [NSEntityDescription insertNewObjectForEntityForName:#"QuestionSet" inManagedObjectContext:[self managedObjectContext]];
qs.id = p_id;
qs.title = p_title;
for (int i = 0; i < [questions count]; i++)
{
NSFetchRequest *questionRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *questionEntity = [NSEntityDescription entityForName:#"Question" inManagedObjectContext:[self managedObjectContext]];
NSPredicate *questionPredicate = [NSPredicate predicateWithFormat:#"(id = %d)", [[[questions objectAtIndex:i] objectForKey:#"id"] intValue]];
[questionRequest setEntity:questionEntity];
[questionRequest setPredicate:questionPredicate];
Question *q = nil;
NSArray *questionObjects = [[self managedObjectContext] executeFetchRequest:questionRequest error:&error];
if (questionObjects == nil){
// Handle errors
}
if ([questionObjects count] > 0)
q = [questionObjects objectAtIndex:0];
else
q = [NSEntityDescription insertNewObjectForEntityForName:#"Question" inManagedObjectContext:[self managedObjectContext]];
q.id = [NSNumber numberWithInt:[[[questions objectAtIndex:i] objectForKey:#"id"] intValue]];
q.question = [[questions objectAtIndex:i] objectForKey:#"text"];
q.answer = [NSNumber numberWithInt:[[[questions objectAtIndex:i] objectForKey:#"ca"] intValue]];
for (int j = 0; j < [[[questions objectAtIndex:i] objectForKey:#"A"] count]; j++)
{
NSFetchRequest *answerRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *answerEntity = [NSEntityDescription entityForName:#"Answer" inManagedObjectContext:[self managedObjectContext]];
NSPredicate *answerPredicate = [NSPredicate predicateWithFormat:#"(id = %d)", [[[[[questions objectAtIndex:i] objectForKey:#"A"] objectAtIndex:j] objectForKey:#"id"] intValue]];
[answerRequest setEntity:answerEntity];
[answerRequest setPredicate:answerPredicate];
Answer *a = nil;
NSArray *answerObjects = [[self managedObjectContext] executeFetchRequest:answerRequest error:&error];
if (answerObjects == nil){
// Handle errors
}
if ([answerObjects count] > 0)
a = [answerObjects objectAtIndex:0];
else
a = [NSEntityDescription insertNewObjectForEntityForName:#"Answer" inManagedObjectContext:[self managedObjectContext]];
a.id = [NSNumber numberWithInt:[[[[[questions objectAtIndex:i] objectForKey:#"A"] objectAtIndex:j] objectForKey:#"id"] intValue]];
a.answer = [[[[questions objectAtIndex:i] objectForKey:#"A"] objectAtIndex:j] objectForKey:#"text"];
a.questions = [a.questions setByAddingObject:q];
q.answers = [q.answers setByAddingObject:a];
[answerRequest release];
}
q.questionsets = [q.questionsets setByAddingObject:qs];
qs.questions = [qs.questions setByAddingObject:q];
[questionRequest release];
}
[questionsetRequest release];
[[self managedObjectContext] save:&error];
[json_string release];
[self loadTrivia];
NSLog(#"After Load: %#", self.questionsets);
}
This function fetches all the QuestionSet objects from the db and stores the array in an ivar.
- (BOOL)loadTrivia
{
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"QuestionSet" inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
self.questionsets = [[self managedObjectContext] executeFetchRequest:request error:&error];
return YES;
}
Just for completeness, here are my description methods in my classes
from QuestionSet.h
- (NSString *)description
{
return [NSString stringWithFormat:#"\
\n\tid: %#\
\n\ttitle: %#\
\n\tquestions: %#\n",
self.id,
self.title,
self.questions];
}
from Question.h
- (NSString *)description
{
return [NSString stringWithFormat:#"\
\n\tid: %#\
\n\tanswer: %#\
\n\tquestion: %#\
\n\tanswers: %#\n",
self.id,
self.answer,
self.question,
self.answers];
}
from Answer.h
- (NSString *)description
{
return [NSString stringWithFormat:#"\
\n\tid: %#\
\n\tanswer: %#\n",
self.id,
self.answer];
}
You shouldn't subclass the description method (Link):
Although the description method does not cause a fault to fire, if you implement a custom description method that accesses the object’s persistent properties, this will cause a fault to fire. You are strongly discouraged from overriding description in this way.
I tested your loadTrivia code (with a different entityName) on my app and it worked fine.
Did you have a look at the NSError (you should initialize it with =nil):
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
Also you should release the NSFetchRequest after execution in - (BOOL)loadTrivia.