7

Ho cercato all'interno di SO ma non ho trovato alcun suggerimento per migliorare le prestazioni sull'eliminazione di oggetto gestito nei dati principali quando si tratta di relazioni.Considerazioni sulle prestazioni sull'eliminazione di oggetti gestiti utilizzando la regola Cascade nei dati principali

Lo scenario è abbastanza semplice. enter image description here

Come potete vedere ci sono tre diverse entità. Ogni entità è collegata in cascata con la successiva. Ad esempio, FirstLevel ha una relazione denominata secondLevels a SecondLevel. La regola di cancellazione da FirstLevel a SecondLevel è Cascade mentre la regola di cancellazione da SecondLevel a FirstLevel è Nullify. Le stesse regole sono applicate tra SecondLevel e ThirdLevel.

Quando voglio cancellare l'intero grafico, ho eseguire un metodo come il seguente:

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]; 
} 

Approfittando della Cascade regola il grafico viene rimosso. Funziona velocemente per pochi oggetti ma riduce le prestazioni di molti oggetti. Inoltre, penso (ma non sono molto sicuro) che questo tipo di cancellazione compia molti round trip sul disco, mi sbaglio?

Quindi, la mia domanda è la seguente: come è possibile rimuovere il grafico senza sfruttare Cascade regola e aumentare le prestazioni, ma, allo stesso tempo, mantenere la coerenza grafico?

Grazie in anticipo.

EDIT

Non riesco a cancellare l'intero file dal momento che ho altre entità mio modello.

EDIT 2

Il codice ho postato è avvolto nel metodo di una sottoclasse NSOperationmain. Questa soluzione consente di eliminare la fase di eliminazione in background. Dal momento che ho sfruttato la Regola Cascade , la cancellazione viene eseguita in modo semi automatico. Elimina solo oggetti root, gli elementi FirstLevel, tramite il ciclo for all'interno del codice postato. In questo modo Core Data farà il resto per me. Quello che mi chiedo è il seguente: è possibile bybass quella operazione di cancellazione semi-automatica e farlo manualmente senza perdere la consistenza del grafico?

+0

Si desidera eliminare l'intero grafico, cioè cancellare tutto lo store persistente o solo alcuni rami? –

+0

L'intero grafico. –

+1

Allora forse ti sarà d'aiuto? Http: //stackoverflow.com/questions/3266084/how-to-remove-all-objects-from-core-data –

risposta

5

Non è possibile fare molto del tempo necessario per attraversare e rimuovere gli oggetti nel database. Tuttavia, puoi farlo in background in modo che l'interfaccia utente non venga bloccata.

Per esempio, qualcosa di simile (codice presuppone ARC - ed è stato appena digitato - non compilato) ...

- (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]; 
    }]; 
} 

nota, che si potrebbe aggiungere un oggetto Rootlevel al vostro modello di dati, e dargli un relazione uno-a-molti con oggetti di primo livello. Quindi, (purché tu abbia un solo oggetto root) tutto ciò che devi fare è cancellare quell'un oggetto root, e cancellerà tutto il resto all'interno di CoreData. Se hai molti oggetti FirstLevel, quella sarebbe la strada da percorrere.

In alternativa, è possibile collegare il contesto "nuovo" direttamente all'archivio permanente, apportare le modifiche e fare in modo che l'altro contesto guardi le notifiche di modifica.

BTW, se si utilizza UIManagedDocument, si ottiene questo tipo di backgrounding gratuito, perché c'è già un contesto genitore in esecuzione sulla propria coda e tutte le modifiche al contesto principale vengono passate al padre per eseguire effettivamente il database funziona.

EDIT

È possibile farlo manualmente, ma è necessario disattivare la regola a cascata. Ho scoperto che voglio che CoreData faccia quanto più possibile per me. Riduce il mio margine di errore.

Se si sta già eliminando un thread in background, come vengono visualizzati i problemi di prestazioni? Devi effettuare una query durante l'eliminazione ... il che significa che stai usando un MOC che fa tutto il lavoro.

È consigliabile seguire una lezione da UIManagedDocument. dovresti avere un MOC che gira su una coda privata. Fa tutto il vero lavoro. Hai un MOC secondario che passa solo lavoro a quella coda di lavoro.

Se si stanno eseguendo query su oggetti non presenti nel grafico che si sta eliminando, potrebbero rimanere bloccati dalle proprietà di serializzazione del coordinatore di archivio permanente. In questo caso, dovresti prendere in considerazione un coordinatore separato o solo due negozi.

In questo modo, è possibile eliminare gli oggetti nel grafico per tutto il tempo che si desidera, pur rispondendo alle richieste per gli altri oggetti.

+0

+1 per il supporto. Sto già eliminando un thread precedente. Potresti spiegare meglio cosa intendi con * potresti collegare il tuo "nuovo" contesto direttamente allo store persistente, apportare le modifiche e fare in modo che l'altro contesto guardi le notifiche di modifica *? Grazie. –

+0

Forse postare l'intero codice di eliminazione quindi ... Per quanto riguarda la seconda parte, è possibile creare più MOC che utilizzano lo stesso NSPersistentStoreCoordinator. Tuttavia, questo serializzerà l'accesso allo store ... Puoi anche creare un NSPersistentStoreCoordinator separato, e poi avrai accesso parallelo allo store ... ma hai altri problemi da affrontare. In generale, la soluzione più semplice è sempre la migliore. –

+0

Grazie per la risposta. La creazione di più MOC potrebbe essere una soluzione valida, ma ho bisogno di eseguire tale eliminazione in un unico passaggio. Vedi la mia seconda modifica. Grazie ancora. –

1

Io di solito attivo il tracciamento di Core Data SQL con -com.apple.CoreData.SQLDebug 1 come descritto qui: http://useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone.html Questo aiuta a verificare che Core Data esegua ciò che mi aspetto che faccia dietro le quinte.

Ti sei assicurato che [moc save: ...] impieghi così tanto tempo, e non l'effettivo recupero per recuperare gli oggetti da eliminare? In tal caso, è possibile recuperare (e quindi eliminare) tali oggetti di primo livello in lotti.

Problemi correlati