2012-03-14 13 views
13

No entiendo cómo funcionan las reglas de eliminación de relaciones en Core Data, al menos más allá de los casos simples descritos en la documentación.Regla de borrado de datos básicos: relación múltiple, eliminar cuando está vacía

La mayoría de estos casos, y la mayoría de las respuestas que he visto aquí, usan un modelo donde el objeto en el lado izquierdo de una relación uno a varios "posee" los objetos en el lado derecho: p. a Person tiene PhoneNumber s, y si elimina a la persona, borrará todos sus números asociados. En ese tipo de casos, la solución es clara: datos básicos se encargará de todo para usted si establece las relaciones de este modo:

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

Lo que me interesa es lo contrario: de A a-muchos relación en la que la "propiedad" se invierte. Por ejemplo, podría extender el código de ejemplo de CoreDataBooks para agregar una entidad Author para recopilar toda la información sobre un único autor en un solo lugar. A Book tiene un autor, pero un autor tiene muchos libros ... pero no nos importan los autores para quienes no enumeramos libros. Por lo tanto, no se debe permitir eliminar Author cuya relación books no está vacía, y eliminar el último Book que hace referencia a un Author particular debe eliminar ese Author.

puedo imaginar un par de maneras de hacer esto manualmente ... lo que no estoy seguro es de:

  • hace Core Data tiene una manera de hacer al menos algo de esto automágicamente, al igual que con relación eliminar reglas?
  • ¿Existe una forma "canónica" preferida para manejar este tipo de situaciones?

Respuesta

13

Puede anular prepareForDeletion en su clase Book y comprobar si el autor tiene otros libros. Si no, puede eliminar el autor.

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

Editar: Para evitar el borrado de un autor de libros que podría anular validateForDelete o aún mejor: no llame deleteObject con un autor de libros en el primer lugar

+2

A menos que haya algo más en juego, esto parece fallar en el caso en que, por ejemplo, los dos libros de un autor se eliminan a la vez. Estoy imprimiendo el valor de author.books.count en mi correspondiente prepareForDeletion y es 2 para ambos libros. Entonces el autor nunca se borra. (los nombres de clase han cambiado para coincidir con la pregunta, pero las relaciones son las mismas.) –

1

Rickstr,

Comprobar a continuación para las relaciones para obtener sus dos criterios hechos.

  1. Autor - (Denegar) - >> Libros

eliminación de un autor cuya relación de libros es que no debería permitirse

DENY no vacía : Si hay al menos un objeto en el destino de la relación, entonces el objeto de origen no se puede eliminar.

  1. libro - (cascada) -> Autor

borrar el último libro hace referencia a un autor en particular debe eliminar esa Autor

No se puede eliminar el Autor, como dice nuestra primera regla, si hay libros que no estén vacíos, no se deben eliminar. Si no están presentes, el autor se borrará.

Creo que teóricamente debería funcionar. Avísame si funciona o no.

+0

'Autor - (Denegar) - >> Libros 'es bueno, pero' Libro - (Cascada) -> Autor' hace que los autores sean eliminados tan pronto como el primero el libro de ese autor es eliminado (O eso o estoy haciendo algo mal.) – rickster

+0

Pero el mismo autor está ligado con la relación DENY correcta, así que teóricamente no se eliminará, ya que tiene otro libro. –

1

De forma similar a la solución de Tim, puede anular el método willSave en su subclase Autor NSManagedObject. Tenga en cuenta que si utiliza la solución de Tim, le recomiendo que filtre los libros establecidos para los libros que no se han eliminado; De esta forma, si elimina todos los libros del autor al mismo tiempo, el autor se eliminará.

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