How can I duplicate or copy a managed entity with underlying data?

I have a managed entity ("A") that contains various attributes and relationship types, and its relationships also have their own attributes and relationships. What I would like to do is to "copy" or "duplicate" the entire graph of the object embedded in the object "A", and thereby create a new object "B", which is very similar to "A".

To be more specific, none of the relationships contained in β€œB” (or its children) should point to objects associated with β€œA”. There must be a completely new graphic object with the same relationships, and all objects have the same attributes, but, of course, different identifiers.

There is an obvious manual way to do this, but I was hoping to learn about simpler ways to do this, which was not completely obvious from the Core Data documentation.

TIA!

+49
cocoa core-data nsmanagedobject
Apr 28 '10 at 3:22 a.m.
source share
15 answers

Here is the class that I created to perform a "deep copy" of managed objects: attributes and relationships. Note that this does not check for object loops in the object graph. (Thanks to Jaanus for the starting point ...)

@interface ManagedObjectCloner : NSObject { } +(NSManagedObject *)clone:(NSManagedObject *)source inContext:(NSManagedObjectContext *)context; @end @implementation ManagedObjectCloner +(NSManagedObject *) clone:(NSManagedObject *)source inContext:(NSManagedObjectContext *)context{ NSString *entityName = [[source entity] name]; //create new object in data store NSManagedObject *cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; //loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[source valueForKey:attr] forKey:attr]; } //Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName]; for (NSRelationshipDescription *rel in relationships){ NSString *keyName = [NSString stringWithFormat:@"%@",rel]; //get a set of all objects in the relationship NSMutableSet *sourceSet = [source mutableSetValueForKey:keyName]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [ManagedObjectCloner clone:relatedObject inContext:context]; [clonedSet addObject:clonedRelatedObject]; } } return cloned; } @end 
+55
May 29 '10 at 21:30
source share

These answers made me really close, although they did have some flaws:

The first time I took ZS advice and made it a category in NSManagedObject, it seemed a little cleaner to me.

2nd, My object graph contains a one relationship, so I started with a levous example, but note that the levous example does not clone an object in the case of a one relationship. This will crash (attempt to save the NSMO from one context in another context). I turned to this in the following example.

Thirdly, I provided a cache of already cloned objects, this prevents cloning of objects twice and therefore is duplicated in a new graph of objects, and also prevents loops.

Fourth, I added a blacklist (a list of Entity types for cloning). I did this in part to solve one of the shortcomings of my final decision, which I will discuss below.

NOTE. If you use what I understand as a best practice for CoreData, always providing backward relationships, then this will probably clone all objects that are related to the object you want to clone. If you use inversions and you have one root object that knows about all the other objects, then you are likely to clone all of this. My solution was to add a blacklist and pass to the Entity type, which, as I knew, was the parent of one of the objects that I wanted to clone. This seems to work for me. :)

Happy cloning!

 // NSManagedObject+Clone.h #import <CoreData/CoreData.h> @interface NSManagedObject (Clone) - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSArray *)namesOfEntitiesToExclude; @end // NSManagedObject+Clone.m #import "NSManagedObject+Clone.h" @implementation NSManagedObject (Clone) - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary *)alreadyCopied exludeEntities:(NSArray *)namesOfEntitiesToExclude { NSString *entityName = [[self entity] name]; if ([namesOfEntitiesToExclude containsObject:entityName]) { return nil; } NSManagedObject *cloned = [alreadyCopied objectForKey:[self objectID]]; if (cloned != nil) { return cloned; } //create new object in data store cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; [alreadyCopied setObject:cloned forKey:[self objectID]]; //loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[self valueForKey:attr] forKey:attr]; } //Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName]; for (NSString *relName in [relationships allKeys]){ NSRelationshipDescription *rel = [relationships objectForKey:relName]; NSString *keyName = rel.name; if ([rel isToMany]) { //get a set of all objects in the relationship NSMutableSet *sourceSet = [self mutableSetValueForKey:keyName]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude]; [clonedSet addObject:clonedRelatedObject]; } }else { NSManagedObject *relatedObject = [self valueForKey:keyName]; if (relatedObject != nil) { NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude]; [cloned setValue:clonedRelatedObject forKey:keyName]; } } } return cloned; } - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSArray *)namesOfEntitiesToExclude { return [self cloneInContext:context withCopiedCache:[NSMutableDictionary dictionary] exludeEntities:namesOfEntitiesToExclude]; } @end 
+41
Sep 30 '11 at 16:35
source share

I updated user353759 response to support toOne relationship.

 @interface ManagedObjectCloner : NSObject { } +(NSManagedObject *)clone:(NSManagedObject *)source inContext:(NSManagedObjectContext *)context; @end @implementation ManagedObjectCloner +(NSManagedObject *) clone:(NSManagedObject *)source inContext:(NSManagedObjectContext *)context{ NSString *entityName = [[source entity] name]; //create new object in data store NSManagedObject *cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; //loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[source valueForKey:attr] forKey:attr]; } //Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName]; for (NSString *relName in [relationships allKeys]){ NSRelationshipDescription *rel = [relationships objectForKey:relName]; NSString *keyName = [NSString stringWithFormat:@"%@",rel]; if ([rel isToMany]) { //get a set of all objects in the relationship NSMutableSet *sourceSet = [source mutableSetValueForKey:keyName]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [ManagedObjectCloner clone:relatedObject inContext:context]; [clonedSet addObject:clonedRelatedObject]; } }else { [cloned setValue:[source valueForKey:keyName] forKey:keyName]; } } return cloned; } 
+24
Mar 15 '11 at 17:00
source share

This is @Derricks answer, modified to support the new iOS 6.0 contacts ordered for many by polling the relationship to see if it is ordered. While I was there, I added a simpler method for the usual case of cloning within the same NSManagedObjectContext.

 // // NSManagedObject+Clone.h // Tone Poet // // Created by Mason Kramer on 5/31/13. // Copyright (c) 2013 Mason Kramer. The contents of this file are available for use by anyone, for any purpose whatsoever. // #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @interface NSManagedObject (Clone) { } -(NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary *)alreadyCopied exludeEntities:(NSArray *)namesOfEntitiesToExclude; -(NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSArray *)namesOfEntitiesToExclude; -(NSManagedObject *) clone; @end // // NSManagedObject+Clone.m // Tone Poet // // Created by Mason Kramer on 5/31/13. // Copyright (c) 2013 Mason Kramer. The contents of this file are available for use by anyone, for any purpose whatsoever. // #import "NSManagedObject+Clone.h" @implementation NSManagedObject (Clone) -(NSManagedObject *) clone { return [self cloneInContext:[self managedObjectContext] exludeEntities:@[]]; } - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary *)alreadyCopied exludeEntities:(NSArray *)namesOfEntitiesToExclude { NSString *entityName = [[self entity] name]; if ([namesOfEntitiesToExclude containsObject:entityName]) { return nil; } NSManagedObject *cloned = [alreadyCopied objectForKey:[self objectID]]; if (cloned != nil) { return cloned; } //create new object in data store cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; [alreadyCopied setObject:cloned forKey:[self objectID]]; //loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[self valueForKey:attr] forKey:attr]; } //Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName]; for (NSString *relName in [relationships allKeys]){ NSRelationshipDescription *rel = [relationships objectForKey:relName]; NSString *keyName = rel.name; if ([rel isToMany]) { if ([rel isOrdered]) { NSMutableOrderedSet *sourceSet = [self mutableOrderedSetValueForKey:keyName]; NSMutableOrderedSet *clonedSet = [cloned mutableOrderedSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude]; [clonedSet addObject:clonedRelatedObject]; [clonedSet addObject:clonedRelatedObject]; } } else { NSMutableSet *sourceSet = [self mutableSetValueForKey:keyName]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude]; [clonedSet addObject:clonedRelatedObject]; } } } else { NSManagedObject *relatedObject = [self valueForKey:keyName]; if (relatedObject != nil) { NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude]; [cloned setValue:clonedRelatedObject forKey:keyName]; } } } return cloned; } -(NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSArray *)namesOfEntitiesToExclude { return [self cloneInContext:context withCopiedCache:[NSMutableDictionary dictionary] exludeEntities:namesOfEntitiesToExclude]; } @end 
+15
May 31 '13 at 20:38
source share

I noticed a couple of errors with current answers. First, something looks like it mutates a lot of objects related to many, as their repetition repeats. Secondly, I'm not sure that something has changed in the API, but using the NSRelationshipDescription String NSRelationshipDescription as an key, exceptions were thrown when capturing these related objects.

I made a few tweaks, did some basic testing, and it seems to work. If someone wants to explore further, that would be great!

 @implementation NSManagedObjectContext (DeepCopy) -(NSManagedObject *) clone:(NSManagedObject *)source{ NSString *entityName = [[source entity] name]; //create new object in data store NSManagedObject *cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self]; //loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:self] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[source valueForKey:attr] forKey:attr]; } //Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:self] relationshipsByName]; for (NSString *relName in [relationships allKeys]){ NSRelationshipDescription *rel = [relationships objectForKey:relName]; if ([rel isToMany]) { //get a set of all objects in the relationship NSArray *sourceArray = [[source mutableSetValueForKey:relName] allObjects]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:relName]; for(NSManagedObject *relatedObject in sourceArray) { NSManagedObject *clonedRelatedObject = [self clone:relatedObject]; [clonedSet addObject:clonedRelatedObject]; } } else { [cloned setValue:[source valueForKey:relName] forKey:relName]; } } return cloned; } @end 
+8
Nov 10 2018-11-11T00:
source share

I modified Derrick's answer , which worked fine for me, to support ordered relationships available in iOS 5.0 and Mac OS X 10.7:

 // // NSManagedObject+Clone.h // #import <CoreData/CoreData.h> #ifndef CD_CUSTOM_DEBUG_LOG #define CD_CUSTOM_DEBUG_LOG NSLog #endif @interface NSManagedObject (Clone) - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context excludeEntities:(NSArray *)namesOfEntitiesToExclude; @end // // NSManagedObject+Clone.m // #import "NSManagedObject+Clone.h" @interface NSManagedObject (ClonePrivate) - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary **)alreadyCopied excludeEntities:(NSArray *)namesOfEntitiesToExclude; @end @implementation NSManagedObject (Clone) - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary **)alreadyCopied excludeEntities:(NSArray *)namesOfEntitiesToExclude { if (!context) { CD_CUSTOM_DEBUG_LOG(@"%@:%@ Try to clone NSManagedObject in the 'nil' context.", THIS_CLASS, THIS_METHOD); return nil; } NSString *entityName = [[self entity] name]; if ([namesOfEntitiesToExclude containsObject:entityName]) { return nil; } NSManagedObject *cloned = nil; if (alreadyCopied != NULL) { cloned = [*alreadyCopied objectForKey:[self objectID]]; if (cloned) { return cloned; } // Create new object in data store cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; [*alreadyCopied setObject:cloned forKey:[self objectID]]; } else { CD_CUSTOM_DEBUG_LOG(@"%@:%@ NULL pointer was passed in 'alreadyCopied' argument.", THIS_CLASS, THIS_METHOD); } // Loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[self valueForKey:attr] forKey:attr]; } // Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName]; NSArray *relationshipKeys = [relationships allKeys]; for (NSString *relName in relationshipKeys) { NSRelationshipDescription *rel = [relationships objectForKey:relName]; NSString *keyName = [rel name]; if ([rel isToMany]) { if ([rel isOrdered]) { // Get a set of all objects in the relationship NSMutableOrderedSet *sourceSet = [self mutableOrderedSetValueForKey:keyName]; NSMutableOrderedSet *clonedSet = [cloned mutableOrderedSetValueForKey:keyName]; for (id relatedObject in sourceSet) { //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied excludeEntities:namesOfEntitiesToExclude]; if (clonedRelatedObject) { [clonedSet addObject:clonedRelatedObject]; } } } else { // Get a set of all objects in the relationship NSMutableSet *sourceSet = [self mutableSetValueForKey:keyName]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName]; for (id relatedObject in sourceSet) { //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied excludeEntities:namesOfEntitiesToExclude]; if (clonedRelatedObject) { [clonedSet addObject:clonedRelatedObject]; } } } } else { NSManagedObject *relatedObject = [self valueForKey:keyName]; if (relatedObject) { NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied excludeEntities:namesOfEntitiesToExclude]; [cloned setValue:clonedRelatedObject forKey:keyName]; } } } return cloned; } - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context excludeEntities:(NSArray *)namesOfEntitiesToExclude { NSMutableDictionary* mutableDictionary = [NSMutableDictionary dictionary]; return [self cloneInContext:context withCopiedCache:&mutableDictionary excludeEntities:namesOfEntitiesToExclude]; } @end 
+6
Mar 03 2018-12-12T00:
source share

Something like that? (unverified). This will be the β€œmanual mode” that you mentioned, but it will automatically synchronize with model changes and therefore you do not need to manually enter all attribute names.

Swift 3:

 extension NSManagedObject { func shallowCopy() -> NSManagedObject? { guard let context = managedObjectContext, let entityName = entity.name else { return nil } let copy = NSEntityDescription.insertNewObject(forEntityName: entityName, into: context) let attributes = entity.attributesByName for (attrKey, _) in attributes { copy.setValue(value(forKey: attrKey), forKey: attrKey) } return copy } } 

Objective-C:

 @interface MyObject (Clone) - (MyObject *)clone; @end @implementation MyObject (Clone) - (MyObject *)clone{ MyObject *cloned = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:moc]; NSDictionary *attributes = [[NSEntityDescription entityForName:@"MyObject" inManagedObjectContext:moc] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[self valueForKey:attr] forKey:attr]; } return cloned; } @end 

This will return you a clone with all attributes and the relationship will not be copied.

+4
Apr 28 '10 at 15:50
source share

I had a real need to get around the bulk copy problem that @derrick confirmed in his original answer. I modified the version of MasonK. This is not much of the elegance that was in previous versions; but it seems to solve the key problem (unintentional duplicates of similar objects) in my application.

 // // NSManagedObject+Clone.h #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @interface NSManagedObject (Clone) { } -(NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary *)alreadyCopied exludeEntities:(NSMutableArray *)namesOfEntitiesToExclude isFirstPass:(BOOL)firstPass; -(NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSMutableArray *)namesOfEntitiesToExclude; -(NSManagedObject *) clone; @end // // NSManagedObject+Clone.m // #import "NSManagedObject+Clone.h" @implementation NSManagedObject (Clone) -(NSManagedObject *) clone { NSMutableArray *emptyArray = [NSMutableArray arrayWithCapacity:1]; return [self cloneInContext:[self managedObjectContext] exludeEntities:emptyArray]; } - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context withCopiedCache:(NSMutableDictionary *)alreadyCopied exludeEntities:(NSMutableArray *)namesOfEntitiesToExclude isFirstPass:(BOOL)firstPass { NSString *entityName = [[self entity] name]; if ([namesOfEntitiesToExclude containsObject:entityName]) { return nil; } NSManagedObject *cloned = [alreadyCopied objectForKey:[self objectID]]; if (cloned != nil) { return cloned; } //create new object in data store cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; [alreadyCopied setObject:cloned forKey:[self objectID]]; //loop through all attributes and assign then to the clone NSDictionary *attributes = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] attributesByName]; for (NSString *attr in attributes) { [cloned setValue:[self valueForKey:attr] forKey:attr]; } //Inverse relationships can cause all of the entities under one area to get duplicated //This is the reason for "isFirstPass" and "excludeEntities" if (firstPass == TRUE) { [namesOfEntitiesToExclude addObject:entityName]; firstPass=FALSE; } //Loop through all relationships, and clone them. NSDictionary *relationships = [[NSEntityDescription entityForName:entityName inManagedObjectContext:context] relationshipsByName]; for (NSString *relName in [relationships allKeys]){ NSRelationshipDescription *rel = [relationships objectForKey:relName]; NSString *keyName = rel.name; if ([rel isToMany]) { if ([rel isOrdered]) { NSMutableOrderedSet *sourceSet = [self mutableOrderedSetValueForKey:keyName]; NSMutableOrderedSet *clonedSet = [cloned mutableOrderedSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude isFirstPass:firstPass]; if (clonedRelatedObject != nil) { [clonedSet addObject:clonedRelatedObject]; [clonedSet addObject:clonedRelatedObject]; } } } else { NSMutableSet *sourceSet = [self mutableSetValueForKey:keyName]; NSMutableSet *clonedSet = [cloned mutableSetValueForKey:keyName]; NSEnumerator *e = [sourceSet objectEnumerator]; NSManagedObject *relatedObject; while ( relatedObject = [e nextObject]){ //Clone it, and add clone to set NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude isFirstPass:firstPass]; if (clonedRelatedObject != nil) { [clonedSet addObject:clonedRelatedObject]; } } } } else { NSManagedObject *relatedObject = [self valueForKey:keyName]; if (relatedObject != nil) { NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context withCopiedCache:alreadyCopied exludeEntities:namesOfEntitiesToExclude isFirstPass:firstPass]; if (clonedRelatedObject != nil) { [cloned setValue:clonedRelatedObject forKey:keyName]; } } } } return cloned; } -(NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context exludeEntities:(NSMutableArray *)namesOfEntitiesToExclude { return [self cloneInContext:context withCopiedCache:[NSMutableDictionary dictionary] exludeEntities:namesOfEntitiesToExclude isFirstPass:TRUE]; } @end 
+4
Jul 24 '13 at 4:10
source share

What you ask for is called a "deep copy." Since this can be very expensive (as with unlimited memory usage) and very difficult to get right (look at the loops in the object graph), Core Data will not provide you this opportunity.

Often there is an architecture that avoids the need. Instead of making a copy of the entire graph of the objects, perhaps you can create a new object that encapsulates the differences (or future differences) that you would have if you copied the graph of objects and then referenced only the original graph. In other words, create an instance of the new "customizer" object and do not copy the entire graph of the object. For example, consider a set of ordinary houses. Each of them has the same equipment and appliances, but the owner can customize the paint and furniture. Instead of deep copying the entire house graph for each owner, there is an object "painting and furniture" that refers to the owner and model of the house - for each owner.

+3
Apr 28 '10 at 16:53
source share

Best DEEP COPY category with relationship preservation https://gist.github.com/advantis/7642084

+3
Nov 07 '14 at 1:10
source share

This is called a "deep copy." Since it can be surprisingly expensive, many languages ​​/ libraries do not support it out of the box and require you to roll your own. Cocoa, unfortunately, is one of them.

+2
Apr 28 '10 at 15:33
source share

Here you have my swift 3 approach:

 func shallowCopy(copyRelations: Bool) -> NSManagedObject? { guard let context = managedObjectContext, let entityName = entity.name else { return nil } let copy = NSEntityDescription.insertNewObject(forEntityName: entityName, into: context) let attributes = entity.attributesByName for (attrKey, _) in attributes { copy.setValue(value(forKey: attrKey), forKey: attrKey) } if copyRelations { let relations = entity.relationshipsByName for (relKey, relValue) in relations { if relValue.isToMany { let sourceSet = mutableSetValue(forKey: relKey) let clonedSet = copy.mutableSetValue(forKey: relKey) let enumerator = sourceSet.objectEnumerator() while let relatedObject = enumerator.nextObject() { let clonedRelatedObject = (relatedObject as! NSManagedObject).shallowCopy(copyRelations: false) clonedSet.add(clonedRelatedObject!) } } else { copy.setValue(value(forKey: relKey), forKey: relKey) } } } return copy } 
+2
May 15 '17 at 16:31
source share

also:

 [clone setValuesForKeysWithDictionary:[item dictionaryWithValuesForKeys:[properties allKeys]]]; [clone setValuesForKeysWithDictionary:[item dictionaryWithValuesForKeys:[attributes allKeys]]]; 
0
Aug 31 '10 at 13:25
source share

If you want to link only entities in the relationship hierarchy, you need to add the following code to Dmitry’s solution

Between this

 NSString *entityName = [[self entity] name]; 

HERE if ([namesOfEntitiesToExclude containsObject: entityName]) {

 NSMutableArray *arrayToOnlyRelate = [NSMutableArray arrayWithObjects:@"ENTITY 1",@"ENTITY 2",@"ENTITY 3", nil]; if ([arrayToOnlyRelate containsObject:entityName]) { return self; } 
0
Feb 20 '15 at 10:01
source share

I take this at https://gist.github.com/jpmhouston/7958fceae9216f69178d4719a3492577

  • passes rel.inverseRelationship.name to a recursive method so as not to visit inverse relationships and not support a set of alreadyCopied objects

  • shallow or deep copies

  • accepts key paths of a relationship to a non- clone, but either omit or simply copy, if the opposite is a to-many relation

  • workaround for orderly relationships with many ending in reverse - just iterate over the original entities back :) I'm not sure if this is a good idea or if it even works all the time

Feedback and comments are welcome, especially if someone can comment on Benjohn's comment about the wrong order above "The job for this is to build a complete ordered set and then assign using a primitive version of KVO." and can improve my orderly, by-many workaround.

, MagicalRecord, , , , .

0
31 '16 17:57
source share



All Articles