Как я могу копировать или скопировать Базовый Управляемый объект Данных?

У меня есть управляемый объект ("A"), который содержит различные атрибуты и типы отношений, и его отношения также имеют свои собственные атрибуты и отношения. То, что я хотел бы сделать, должно "скопировать" или "копировать" весь граф объектов, базированный в объекте "A", и таким образом создание нового объекта "B", который очень похож на "A".

Чтобы быть точнее, ни одно из отношений, содержавших "B" (или его дети), не должно указывать на объекты, связанные с "A". Должен быть совершенно новый граф объектов с подобными неповрежденными отношениями, и все объекты, имеющие те же атрибуты, но конечно другой идентификатор.

Существует очевидный ручной способ сделать это, но я надеялся узнать о более простом средстве выполнения поэтому, которое не было полностью очевидно из Базовой документации Данных.

TIA!

54
задан Douwe Maan 28 April 2010 в 05:46
поделиться

5 ответов

Вот класс, который я создал для выполнения "глубокого копирования" управляемых объектов: атрибутов и отношений. Обратите внимание, что он не проверяет циклы в графе объектов. (Спасибо Jaanus за отправную точку...)

@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
57
ответ дан 7 November 2019 в 07:38
поделиться

То, что вы просите, называется «глубокой копией». Поскольку это может быть очень дорогостоящим (например, при неограниченном использовании памяти) и очень сложным для правильного выполнения (учитывайте циклы в графе объектов), Core Data не предоставляет вам эту возможность.

Однако часто существует архитектура, в которой нет необходимости. Вместо того, чтобы делать копию всего графа объекта, возможно, вы можете создать новую сущность, которая инкапсулирует различия (или будущие различия), которые у вас были бы, если бы вы скопировали граф объекта, а затем ссылались бы только на исходный граф. Другими словами, создайте экземпляр новой сущности «настройщика» и не копируйте весь граф объекта. Например, рассмотрим набор рядных домов. Каждый из них имеет идентичный каркас и технику, но владелец может настроить краску и мебель. Вместо того чтобы копировать всю диаграмму дома для каждого владельца, создайте объект «картина и мебель» - который ссылается на владельца и модель дома - для каждого владельца.

4
ответ дан 7 November 2019 в 07:38
поделиться

Что-то вроде этого? (непроверено) Это будет упомянутый вами «ручной способ», но он будет автоматически синхронизироваться с изменениями модели и т.п., поэтому вам не придется вручную вводить все имена атрибутов.

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

Это вернет вам клон со всеми атрибутами и без скопированных отношений.

4
ответ дан 7 November 2019 в 07:38
поделиться

Это называется "глубокая копия". Поскольку это может быть удивительно дорого, многие языки/библиотеки не поддерживают его из коробки и требуют, чтобы вы создали свой собственный. Cocoa, к сожалению, один из них.

2
ответ дан 7 November 2019 в 07:38
поделиться

Также:

[clone setValuesForKeysWithDictionary:[item dictionaryWithValuesForKeys:[properties allKeys]]];
[clone setValuesForKeysWithDictionary:[item dictionaryWithValuesForKeys:[attributes allKeys]]];
0
ответ дан 7 November 2019 в 07:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: