2012-03-14 15 views
13

Sono un po 'confuso su come funzionano le regole di eliminazione per le relazioni nei Core Data, almeno al di là dei semplici casi descritti nella documentazione.Core Data cancella la relazione rule-to-many, cancella quando è vuota

Molti di questi casi, e la maggior parte delle risposte che ho visto per le domande qui, utilizzano un modello in cui l'oggetto sul lato sinistro di una relazione uno-a-molti "possiede" gli oggetti sul lato destro: ad es. a Person ha PhoneNumber s, e se si elimina la persona si eliminano tutti i loro numeri associati. In questo tipo di caso, la soluzione è chiara: Core Data si occuperà di tutto per voi, se si impostano le relazioni in questo modo:

Person  --(cascade)-->> PhoneNumber 
PhoneNumber --(nullify)--> Person 

Quello che mi interessa è l'opposto: A a-molti in cui il "proprietà" è invertita. Ad esempio, potrei estendere il codice di esempio CoreDataBooks per aggiungere un'entità Author per raccogliere tutte le informazioni su un autore unico in un unico posto. A Book ha un autore, ma un autore ha molti libri ... ma a noi non interessa gli autori per i quali non elenciamo libri. Pertanto, l'eliminazione di un Author la cui relazione books non è vuota non dovrebbe essere consentita e l'eliminazione dell'ultimo Book con riferimento a un particolare Author dovrebbe eliminare tale Author.

posso immaginare un paio di modi per farlo manualmente ... quello che non sono sicuro è:

  • ha Core Data ha un modo di fare almeno una parte di questo automaticamente, come con rapporto elimina le regole?
  • c'è un modo "canonico" per gestire questo tipo di situazione?

risposta

13

È possibile ignorare lo prepareForDeletion nella classe Book e verificare se l'autore ha altri libri. Altrimenti potresti cancellare l'autore.

- (void)prepareForDeletion { 
    Author *author = self.author; 
    if (author.books.count == 1) { // only the book itself 
     [self.managedObjectContext deleteObject:author]; 
    } 
} 

Modifica: Per evitare la cancellazione di un autore con i libri si può ignorare validateForDelete o meglio: non chiamare DeleteObject con un autore di libri in primo luogo

+2

A meno che non succeda qualcos'altro, questo sembra fallire nel caso in cui, ad esempio, entrambi i libri di un autore vengano cancellati contemporaneamente. Sto stampando il valore di author.books.count nel mio corrispondente prepareForDeletion ed è 2 per entrambi i libri. Quindi l'autore non viene mai cancellato. (i nomi delle classi vengono modificati per corrispondere alla domanda ma le relazioni sono uguali.) –

1

Rickstr,

Controllare sotto per le relazioni per ottenere i tuoi due criteri.

  1. Autore - (Deny) - >> Libri

l'eliminazione di un autore il cui rapporto di libri non è vuota non dovrebbe essere consentito

DENY : Se è presente almeno un oggetto nella destinazione della relazione, non è possibile eliminare l'oggetto di origine.

  1. Book - (Cascade) -> Autore

l'eliminazione dell'ultimo libro fa riferimento a un particolare autore dovrebbe eliminare tale Autore

Non è possibile cancellare la L'autore, come dice la nostra prima regola, se ci sono libri che non sono vuoti non dovrebbe essere cancellato. Se non sono presenti, l'Autore viene cancellato.

Penso che teoricamente dovrebbe funzionare. Fammi sapere, se funziona o no.

+0

'Autore - (Nega) - >> Libri' è buono, ma' Libro - (Cascade) -> Autore' fa sì che gli autori vengano eliminati non appena il primo il libro di quell'autore è cancellato. (O quello o sto facendo qualcosa di sbagliato.) – rickster

+0

Ma lo stesso Autore è legato con la relazione DENY a destra, Quindi in teoria non sarà cancellato, come ha un altro libro. –

1

Analogamente alla soluzione di Tim, è possibile sostituire il metodo willSave nella sottoclasse Autore NSManagedObject. Si noti che se si utilizza la soluzione di Tim, consiglio vivamente di filtrare i libri impostati per i libri che non sono stati cancellati; in questo modo se si eliminano tutti i libri dell'autore contemporaneamente, l'autore verrà comunque eliminato.

- (void)willSave { 
    if (!self.isDeleted) { 
     NSPredicate *notDeletedPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary<NSString *,id> *bindings) { 
      return ![(NSManagedObject *)evaluatedObject isDeleted]; 
     }]; 
     NSSet *filteredBooks = [self.books filteredSetUsingPredicate:notDeletedPredicate]; 
     if (filteredBooks.count == 0) 
      [self.managedObjectContext deleteObject:self]; 
    } 
    [super willSave]; 
}