7

Szukałem w ramach SO, ale nie znalazłem żadnych sugestii, aby zwiększyć wydajność usuwania obiektu zarządzanego w danych podstawowych podczas rozwiązywania relacji.Uwagi dotyczące wydajności podczas usuwania obiektów zarządzanych przy użyciu reguły Cascade w danych podstawowych

Scenariusz jest dość prosty. enter image description here

Jak widać, istnieją trzy różne jednostki. Każda jednostka jest połączona kaskadowo z kolejną. Na przykład FirstLevel ma relację o nazwie secondLevels do SecondLevel. Reguła usuwania z FirstLevel do SecondLevel to Cascade, podczas gdy reguła usuwania z SecondLevel do FirstLevel to Nullify. Te same zasady są stosowane między SecondLevel i ThirdLevel.

Kiedy usunąć cały wykres, że wykonuje sposób jak poniżej:

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

Wykorzystując Cascade wykluczyć wykres jest usuwany. Działa to szybko dla kilku obiektów, ale zmniejsza wydajność dla wielu obiektów. Poza tym uważam (ale nie jestem tego pewien), że tego typu usuwanie wykonuje wiele podróży w obie strony na dysk, czy jestem w błędzie?

Moje pytanie brzmi: jak można usunąć wykres bez korzystania z zasady i zwiększenia wydajności, ale jednocześnie zachować spójność wykresów?

Z góry dziękuję.

EDIT

nie mogę usunąć cały plik, ponieważ mam inne podmioty w moim modelu.

EDIT 2

kod I wysłane jest owinięta w sposobem obejmującym NSOperation podklasy main. To rozwiązanie pozwala wyeliminować fazę usuwania w tle. Ponieważ skorzystałem z Cascade Rule, usunięcie odbywa się w sposób półautomatyczny. Usuwam tylko obiekty główne, elementy FirstLevel, za pomocą pętli for w ramach opublikowanego kodu. W ten sposób Core Data zrobi dla mnie resztę. Zastanawiam się, co następuje: czy można obejść tę półautomatyczną operację usuwania i zrobić to ręcznie bez utraty spójności wykresu?

+0

Czy chcesz usunąć cały wykres, to znaczy usunąć cały trwały sklep lub tylko niektóre gałęzie? –

+0

Cały wykres. –

+1

Może to ci pomóc? Http: //stackoverflow.com/questions/3266084/how-to-remove-all-objects-from-core-data –

Odpowiedz

5

Nie można wiele zrobić, aby przejść i usunąć obiekty z bazy danych. Możesz jednak zrobić to w tle, aby interfejs nie został zablokowany.

Na przykład coś takiego (kod zakłada ARC - i po prostu wpisane - nie skompilowany) ...

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

uwaga, że ​​można dodać obiekt RootLevel do modelu danych i nadać mu relacja jeden-do-wielu do obiektów pierwszego poziomu. Następnie (tak długo, jak masz tylko jeden obiekt główny), wszystko co musisz zrobić, to usunąć ten jeden obiekt główny, a to usunie wszystko inne w CoreData. Jeśli masz dużo obiektów FirstLevel, będzie to właściwa droga.

Alternatywnie możesz połączyć swój "nowy" kontekst bezpośrednio ze sklepem trwałym, wprowadzić zmiany i poprosić inne środowisko kontekstowe o powiadomienia o zmianach.

BTW, jeśli korzystasz z UIManagedDocument, otrzymujesz tego rodzaju tło za darmo, ponieważ istnieje już kontekst nadrzędny uruchomiony we własnej kolejce, a wszystkie zmiany w głównym kontekście są przekazywane do rodzica, aby faktycznie praca z bazą danych.

EDIT

Można to zrobić ręcznie, ale trzeba wyłączyć regułę kaskadowy. Odkryłem, że chcę, aby CoreData robił dla mnie tyle, ile tylko możliwe. Zmniejsza mój margines błędu.

Jeśli już usuwasz w wątku w tle, to jak widzisz problemy z wydajnością? Podczas tego usuwania musisz odpowiadać na pytania ... co oznacza, że ​​używasz MOC, który wykonuje całą pracę.

Powinieneś wziąć lekcję od UIManagedDocument. powinieneś mieć MOC, który działa w prywatnej kolejce. Wykonuje całą prawdziwą pracę. Masz dziecko MOC, które po prostu przekazuje pracę do tej kolejki pracującej.

Jeśli faktycznie szukasz informacji o obiektach, które nie są na usuwanym wykresie, mogą zostać rozłączone przez właściwości serializacji trwałego koordynatora sklepu. Jeśli tak jest, powinieneś rozważyć albo oddzielnego koordynatora, albo po prostu mieć dwa sklepy.

W ten sposób możesz usuwać obiekty na wykresie tak długo, jak chcesz, jednocześnie wciąż reagując na żądania dotyczące innych obiektów.

+0

+1 za wsparcie. Już usuwam w wątku wstecz. Czy mógłbyś lepiej wyjaśnić, co masz na myśli, mówiąc o * możesz połączyć swój "nowy" kontekst bezpośrednio ze sklepem trwałym, wprowadzić zmiany i poprosić inne środowisko kontekstowe o powiadomienia o zmianach *? Dziękuję Ci. –

+0

Może opublikuj cały kod usunięcia, a następnie ... Jeśli chodzi o drugą część, możesz utworzyć wiele MOCów, które używają tego samego NSPersistentStoreCoordinator. Jednak spowoduje to serializację dostępu do sklepu ... Możesz także utworzyć oddzielny NSPersistentStoreCoordinator, a następnie będziesz mieć równoległy dostęp do sklepu ... ale masz inne problemy, którymi możesz się zająć. Ogólnie rzecz biorąc, najprostsze rozwiązanie jest zawsze najlepsze. –

+0

Dziękuję za odpowiedź. Tworzenie wielu MOCów może być prawidłowym rozwiązaniem, ale muszę wykonać perfekcję tego usunięcia w jednym przebiegu. Zobacz moją drugą edycję. Jeszcze raz dziękuję. –

1

zwykle włączyć DANE PODSTAWOWE SQL śledzenia z -com.apple.CoreData.SQLDebug 1 jak opisano tutaj: http://useyourloaf.com/blog/2010/3/11/debugging-core-data-on-the-iphone.html Pomaga to sprawdzenie danych Core robi to, czego oczekuję to zrobić za kulisami.

Czy upewniłeś się, że [moc save: ...] zajmuje tyle czasu, a nie faktyczne żądanie pobrania, aby pobrać obiekty do usunięcia? W takim przypadku można pobierać (a następnie usuwać) te obiekty pierwszego poziomu w partiach.

Powiązane problemy