0
votes

I have an issue with Core Data. I have an entity called "Group", and other entity called "Contact". These entities have a relationship "many to many" between them, because a group could have many contacts (members of the group), and a contact could have many groups (be a member of many groups).

So, this is the relationship:

Group <<----->> Contact

What I need is insert contacts (new or existing) as members of existing groups. What is my issue? Well...I am able to insert them if I create a new contact, but if the contact already exists, Core Data does not overwrite and save it.

Here is my code:

- (void)saveMemberInGroup:(Message *)message
{
    GroupInfo *groupInfo = message.group;
    UserInfo *member = message.user;

    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = [app managedObjectContext];
    NSError *error;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:CONTACT_ENTITY
                                              inManagedObjectContext:context];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"ident == %@", [member ident]]];
    [fetchRequest setEntity:entity];
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

    //Here I check if the contact exists.
    Contact *contact;
    if ([fetchedObjects count] == 0) {
        contact = [NSEntityDescription insertNewObjectForEntityForName:CONTACT_ENTITY
                                                inManagedObjectContext:context];
        [contact setIdent:[NSString stringWithFormat:@"%@", [member ident]]];
    } else {
        contact = [fetchedObjects objectAtIndex:0];
    }

    //Now I make a new request for the group.
    fetchRequest = [[NSFetchRequest alloc] init];
    entity = [NSEntityDescription entityForName:GROUP_ENTITY
                         inManagedObjectContext:context];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"ident == %@", [groupInfo ident]]];
    [fetchRequest setEntity:entity];
    fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

    Group *group = [fetchedObjects objectAtIndex:0];

    //Now, I overwrite the group and the contact.
    [[group members]addObject:contact];
    [[contact memberGroups]addObject:group];

    [context save:&error];
}

Here is my Group entity:

@interface Group : NSManagedObject

@property (nonatomic, retain) NSString *ident;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSMutableSet *members;

@end

And my Contact entity:

@interface Contact : NSManagedObject

@property (nonatomic, retain) NSString *ident;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSMutableSet *memberGroups;

@end

NOTE:

This is really weird...when I check if I have updated the objects successfully, everything seems to be ok, both groups and contacts have their NSSet updated rightly, but when I restart the app (I mean, finalize and start it again, or press "play" in XCode), Core Data only has saved the relationship with the new contacts created!!.

Example:

  1. Create Contact1 and save in Group1.
  2. Create Contact2 and save in Group1.
  3. Existing Contact1 and save in Group2.
  4. Create Contact3 and save in Group2.

If I check Core Data when my app is running, I will have in Group1 (Contact1, Contact2), and in Group2 (Contact1, Contact3).

Then I restart the app and check again Core Data, and now I have in Group1 (Contact1, Contact2), and in Group2 (Contact3)!! Core Data has lost the relationship between Contact1 and Group2, and this happens every time I have a relationship between a group and an existing contact.

What I am doing wrong??

Thanks a lot!.

1

1 Answers

4
votes

You should create the class files for your entities with "Editor -> Create NSManagedObject Subclasses ..." from the Xcode menu. A to-many relationship is represented by an NSSet, not a NSMutableSet, so you cannot modify it directly by adding an object.

Once you have done that, you can add an additional object to group.members with

[group addMembersObject:contact];

or alternatively

[contact addMemberGroupsObject:group];

Core Data updates inverse relationships automatically, so it does not matter which one you choose.