7

Я искал в SO, но я не нашел никаких предложений по увеличению производительности при удалении управляемого объекта в Core Data при работе с отношениями.Оценка производительности при удалении управляемых объектов с использованием правила Cascade в базовых данных

Сценарий довольно прост. enter image description here

Как вы можете видеть, существуют три разных объекта. Каждый объект связан в каскаде со следующим. Например, FirstLevel имеет отношение под названием secondLevels к SecondLevel. Правило удаления от FirstLevel до SecondLevel: Каскад, а правило удаления от SecondLevel до FirstLevel - Nullify. Те же правила применяются между SecondLevel и ThirdLevel.

Когда я хочу, чтобы удалить весь граф, я выполнить метод, как следующее:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"FirstLevel" inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 

NSError *error = nil; 
NSArray *items = [context executeFetchRequest:fetchRequest error:&error]; 
[fetchRequest release];  

// delete roots object and let Core Data to do the rest... 
for (NSManagedObject *managedObject in items) { 
    [context deleteObject:managedObject]; 
} 

Воспользовавшись Cascade господствовать граф удаляется. Это работает быстро для нескольких объектов, но снижает производительность для многих объектов. Кроме того, я думаю (но я не очень уверен), что этот тип удаления совершает много круговых поездок на диск, я ошибаюсь?

Итак, мой вопрос в следующем: как можно удалить график, не используя Cascade правила и повышения производительности, но в то же время поддерживать согласованность графиков?

Заранее спасибо.

EDIT

Я не могу удалить весь файл, так как у меня есть другие объекты в моей модели.

РЕДАКТИРОВАТЬ 2

кода я разместил обернут в main методе NSOperation подкласса. Это решение позволяет исключить фазу удаления в фоновом режиме. Так как я воспользовался Правило каскада, удаление выполняется полуавтоматически. Я удаляю только объекты root, объекты FirstLevel, с помощью цикла for внутри опубликованного кода. Таким образом, Core Data сделает для меня все остальное. Меня интересует следующее: возможно ли использовать эту операцию полуавтоматического удаления и выполнять ее вручную без потери согласованности графика?

+0

Do tou хотите удалить весь график, я имею в виду, очистить все постоянное хранилище или просто несколько ветвей? –

+0

Весь график. –

+1

Тогда вам это поможет? Http: //stackoverflow.com/questions/3266084/how-to-remove-all-objects-from-core-data –

ответ

5

Вы не можете многое сделать в отношении времени, необходимого для перемещения и удаления объектов в базе данных. Однако вы можете сделать это в фоновом режиме, чтобы пользовательский интерфейс не блокировался.

Например, что-то вроде (код предполагает ARC - и просто напечатал - не компилируется) ...

- (void)deleteAllLevelsInMOC:(NSManagedObjectContext*)moc 
{ 
    // Create a context with a private queue, so access happens on a separate thread. 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    // Insert this context into the current context hierarchy 
    context.parentContext = context; 
    // Execute the block on the queue of the context 
    context.performBlock:^{ 
      NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"FirstLevel"]; 
      // This will not load any properties - just object id 
      fetchRequest.includesPropertyValues = NO; 
      // Iterate over all first-level objects, deleting each one 
      [[context executeFetchRequest:fetchRequest error:0] 
       enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
       [context deleteObject:obj]; 
      }]; 
      // Push the changes out of the context 
      [context save:0]; 
    }]; 
} 

Обратите внимание, что вы могли бы добавить объект RootLevel к вашей модели данных, и дать ему отношения «один ко многим» к объектам первого уровня. Затем (пока у вас есть только один объект root) все, что вам нужно сделать, это удалить один корневой объект, и он удалит все остальное внутри CoreData. Если у вас много объектов FirstLevel, это будет путь.

В качестве альтернативы вы можете подключить свой «новый» контекст непосредственно к постоянному хранилищу, внести изменения и использовать другой контекстный просмотр уведомлений об изменении.

BTW, если вы используете UIManagedDocument, вы получаете этот вид фона бесплатно, потому что уже есть родительский контекст, запущенный в собственной очереди, и все изменения в основном контексте передаются родительскому объекту работа с базой данных.

EDIT

Вы можете сделать это вручную, но вы должны отключить правило каскада. Я обнаружил, что хочу, чтобы CoreData сделал для меня как можно больше. Это уменьшает мой запас за ошибку.

Если вы уже удаляете фоновый поток, то как вы видите проблемы с производительностью? Вы должны запрашивать во время этого удаления ... что означает, что вы используете MOC, который выполняет всю работу.

Вы должны извлечь урок из UIManagedDocument. вы должны иметь MOC, который работает в частной очереди. Он выполняет всю настоящую работу. У вас есть дочерний MOC, который просто передает работу этой рабочей очереди.

Если вы действительно запрашиваете объекты, не находящиеся в графе, который вы удаляете, их можно повесить на сериализующие свойства координатора постоянного хранилища. Если это так, вы должны рассмотреть либо отдельный координатор, либо просто иметь два магазина.

Таким образом, вы можете удалять объекты на своем графике столько, сколько захотите, но при этом реагируете на запросы других объектов.

+0

+1 для вашей поддержки. Я уже удаляю задний поток. Не могли бы вы лучше объяснить, что вы имеете в виду: * вы могли бы подключить свой «новый» контекст непосредственно к постоянному хранилищу, внести изменения и просмотреть другой контекст для уведомлений об изменениях *? Спасибо. –

+0

Возможно, после этого будет опубликован весь код удаления. Что касается второй части, вы можете создать несколько MOC, которые используют тот же NSPsistentStoreCoordinator. Однако это приведет к сериализации доступа к хранилищу ... Вы также можете создать отдельный NSPsistentStoreCoordinator, а затем у вас будет параллельный доступ к хранилищу ... но у вас есть другие проблемы. В общем, самое простое решение всегда лучше. –

+0

Благодарим вас за ответ. Создание нескольких MOC может быть допустимым решением, но мне нужно перенести это удаление за один проход. См. Мое второе редактирование. Еще раз спасибо. –

1

Обычно я использую трассировку Core Data SQL с помощью -com.apple.CoreData.SQLDebug 1, как описано здесь: http://useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone.html Это помогает проверять, что Core Data выполняет то, что я ожидаю, что он будет делать за кулисами.

Вы уверены, что [moc save: ...] занимает этот длинный, а не фактический выборка для извлечения объектов, которые нужно удалить? Если это так, вы можете получить (и затем удалить) эти объекты первого уровня в пакетах.