views:

129

answers:

2

I have a model with 2 entities: RealEstate and Container

Containers object are already saved onto the persistent store with the following hierarchy:

Container 1
    Container 2
    Container 3
Container 4
    Container 5
        Container 6

Each container has a RealEstate owner (in a given hierarchy the realEstate is always the same) Now I would like create a copy of this hierarchy changing for each containers the owner realEstate. After some tests it seems to me that it's not a trivial problem.

This is a simplified scheme of the model:

RealEstate (entity)
-------------------
name (string attribute)
containers (relation)

Container (entity)
------------------
level (int attribute)
name (string attribute)
parent (self relation to another container)
subcontainers (relation - set of containers)
realEstate (relation)

Basically each containers has a subcontainers relation with self, and a parent relation so for example Container 1 has no parent but subcontainers=[container 2, container 3] etc...

I have 2 questions:

  • if I want to copy a single attribute (NSNumber) should I copy the attribute before assign it to the copied container with something like [newContainer setLevel:[[container level] copy]] because NSNumber is actually a pointer, or it's ok to assign [newContainer setLevel:[container level]] ??
  • how to copy a relation?? I cannot simply copy the subcontainers with [newContainer setSubcontainers:[container subcontainers]] !!

This is what I'm doing:

- (void)copyContainersFromRealEstate:(RealEstate *)sourceRealEstate toRealEstate:(RealEstate *)destinationRealEstate {
    // read all RealEstate Containers to copy
 NSFetchRequest *request = [[NSFetchRequest alloc] init];
 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"realEstate == %@", sourceRealEstate];
 [request setPredicate:predicate];
 [request setEntity: [ NSEntityDescription entityForName:@"Container"
                 inManagedObjectContext:destinationRealEstate.managedObjectContext] ];

 NSError *error;
 NSArray *results = [destinationRealEstate.managedObjectContext executeFetchRequest:request 
                          error:&error];

 if (results == nil) {
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
      abort();
 }
 [request release];

    // *******************************************************
 // copy each caontainer changing the real estate
 Container *newContainer;
 for (Container *container in results) {
      newContainer = (Container *)[NSEntityDescription insertNewObjectForEntityForName:@"Container" 
                 inManagedObjectContext:destinationRealEstate.managedObjectContext];

      [newContainer setRealEstate:destinationRealEstate];
      [newContainer setLevel:[container level]];
      [newContainer setSubcontainers:[container subcontainers]];  // WRONG
      [newContainer setName:[container name]];
      [newContainer setParent:[container parent]];  // WRONG
 }
    // *******************************************************

}

Any help will be appreciated. Thanks

+1  A: 

if I want to copy a single attribute (NSNumber) should I copy the attribute before assign it to the copied container with something like [newContainer setLevel:[[container level] copy]] because NSNumber is actually a pointer, or it's ok to assign [newContainer setLevel:[container level]] ??

Set the value onto the new object, it will handle it even though it is a pointer because Core Data will be writing the value down into the database so it will be translating it to a primitive at some point and "break" that pointer relationship that you are concerned about.

how to copy a relation?? I cannot simply copy the subcontainers with [newContainer setSubcontainers:[container subcontainers]] !!

Just set the objects and Core Data will do the right thing and construct the new relationships correctly. When you pass the NSSet to the new parent object, Core Data will iterate through the objects in the set and create new relationship connections for each one of them to the new parent object.

Marcus S. Zarra
A: 

Thank you for your reply. I'm sorry if write as a new answer but is the only way to post a screenshot.

Just set the objects and Core Data will do the right thing and construct the new relationships correctly. When you pass the NSSet to the new parent object, Core Data will iterate through the objects in the set and create new relationship connections for each one of them to the new parent object.

I understand that coredata will create new relationship connections to the new parent object and automatically make necessary changes, especially if the relation is modeled in both directions, but in my case something goes wrong, maybe due how I designed my relations. Reviewing my code I see that [newContainer setParent:[container parent]]; is not necessary because "parent" and "subcontainers" are inverse relationships, so setting "subcontainers" will automatically set "parent". But even with this change there is something wrong.

To simplify the problem I just made this test:

  • let say that I just want to copy a subtree and not whole tree, for example Container 5 with its child Container 6 (see hierarchy from my first answer)
  • first checks that the relations is right from the source: if I print out sourceRealEstate Container 5 I see: Container5.parent=Container4, Container5.subcontainers=[Container 6]. So it seems that everything is ok into the copy source
  • than start my copy procedure... after that I try to print out in the same way the copied object and I see: Container5.parent=nil (WRONG), Container5.subcontainers=[Container 6] (RIGHT). Than I recheck source Container and I see: *Container 5.parent=Container 4 (RIGHT), Container5.subcontainer=empty (WRONG)

Conclusions: the subcontainers are moved and not copied

This is my model in more detail:


Container.parent relationship:

Container.subcontainers relationship:

ggould75