2
votes

Overview:

  1. I remove an NSManagedObject using the remove methods provided in the autogenerated NSManagedObject subclass
  2. Then I attempt to save the database
  3. The database save is unsuccessful.

.

 - (void)removeEmployees:(NSSet *)values; //Auto generated method in Department.h

However adding of an NSManagedObject using the add method allows the database to be saved successfully

 - (void)addEmployeesObject:(Employee *)value; //Auto generated method in Department.h - works fine

Note: I am using NSManagedObject subclasses generated by XCode.

Entity Details:

  • I have 2 tables (entities) namely "Employee" and "Department"
  • One department can contain multiple employees
  • One employee can only belong to one department

Relationship Details:

  • Relationship from an "Employee" to "Department" is a One to One relationship and is called "whichDepartment". Delete rule is Nullify
  • Relationship from an "Department" to "Employee" is a Many to One relationship and is called "employees". Delete rule is Cascade

Problem:

"Department" class has a method called as mentioned below, after I use this method, the database save is not successful

(void)removeEmployees:(NSSet *)values; //Auto generated method in Department.h //does not work

Code used to Delete:

- (void) removeEmployeesHavingAgeAsZeroWithDepartment: (Department*) department

{
    NSMutableSet *employeesSetToBeRemoved = [[NSMutableSet alloc] init];

    for(Employees *currentEmployee in department.employees)
    {
        if(currentEmployee.age == 0)
        {
            [employeesSetToBeRemoved addObject:currentEmployee];
        }
    }

    [department removeEmployees:employeesSetToBeRemoved]; //causing the problem
}

Code used to save the database

[self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) 
  {NSLog(@"DB saved");}];

Questions:

  1. Why is it that the saving the Database not successful after using the remove methods?
  2. Do I need to implement this method ? currently i don't see any implementation for this method, I can only find it in the header file.
  3. Are my relationships (inverse, delete rules, etc) set up correctly ?

Answer:

  • Pls refer to Jody's answer and comments (May 17 at 4:39), it is explained well as how to debug the problem and find the root cause
2
So its not crashing, it just doesn't remove items? Have you tried saving the context once you call removeEmployees? I know there is a bug in the auto-generated code if you add/remove items from an NSOrderedSet but this should work fine. - JDx
It doesn't crash, but it doesn't remove the records. Adding alone seems to work as mentioned above - user1046037

2 Answers

4
votes

I'm betting you are not saving your context. When you delete an object, it is just marked to be deleted the next time the context is saved.

If you call isDeleted on each of those objects, what do you get back?

EDIT

Ah... I see you are using UIManagedDocument (I can tell by the save call you are using). You should provide full details in your questions, especially when dealing with CoreData because it has so many knobs and interactions.

OK, so, first, UIManagedDocument is a "saveless" architecture. You should not resort to calling saveToURL when using UIManangedDocument.

It will automatically save itself on a background thread. However, you MUST tell it that is has updates to change.

Also, how do you know it is not saving? I know that sounds like a strange question, but its important to know what you are looking at, and how you are making the determination that the document is not saving.

The documentation states that if you want to save, you need to do one of two things.

  1. Use an UndoManager and let it mark things dirty
  2. Call [document updateChangeCount:UIDocumentChangeDone];

Now, the actual save will happen at some undermined time in the future. However, some things (like going into the background) will trigger a save.

Again, how do you know the data did not save?

Are you just looking at a managed object, fetching from the MOC, looking at the file?

Add

[self.database updateChangeCount:UIDocumentChangeDone];

at the end of that delete function, and you data will surely be saved.

EDIT

Unfortunately, if you get error, the background saving can silently fail. Thus, you should be watching for status change notifications, as that's the only notification you will get earn sn error happens.

While you will get a notification when the status changes as a result of an error, you will get no details about the cause of the error. To get that, you will have to override handleError:userInteractionPermitted: in a subclass of UIManagedDocument if you want the actual NSError details.

I'd register for the status change notifications and provide a simple subclass of UIManagedDocument with the handleError:userInteractionPermitted: overridden to log errors. See what that tells you. Hopefully, it will lead you to why your save is not happening.

Also, don't forget that you have to WAIT for the save.

Finally, if you want to see what CoreData is doing at the SQL level, set debugging (-com.apple.CoreData.SQLDebug 1) in command line options to see SQLLite statements.

2
votes

After some investigation, I realized that the database was not getting saved.

Instead of using the auto generated remove method, I used the NSManagedObjectContext's deleteObject method

Fix:

[self.managedObjectContext deleteObject:currentEmployee];