2011-06-11 7 views
19

Supongamos que tengo un NSManagedObject personalizado Department y esto tiene una propiedad que representa una relación de muchos a empleados, es decir, NSSet *employees;.¿Cómo eliminar todos los objetos a través de una relación de datos centrales?

Para un departamento determinado, quiero eliminar todos los objetos en empleados. ¿Cuál es la mejor/mejor forma de hacer esto, por favor?

Así que, hipotéticamente, el código se vería así:

Department.h

@interface Department: NSManagedObject { 
} 
@property (retain) NSString *departmentName; 
@property (retain) NSSet *employees; 
@end 

Department.m

@implementation Department 
@dynamic departmentName; 
@dynamic employees; 

Employee.h

@interface Employee: NSManagedObject { 
} 
@property (retain) NSString *firstName; 
@property (retain) NSString *lastName; 
@property (retain) Department *worksIn; 
@end 

doCoreDataStuff

- (void)doCoreDataStuff:sender { 
    //add a department, give it a couple employees, then try to remove those employees 
    NSEntityDescription *deptEntity = [NSEntityDescription entityForName:@"Department" 
               inManagedObjectContext:self.managedObjectContext]; 
    Department *dept = [Department alloc] initWithEntity:deptEntity 
          insertIntoManagedObjectContext:self.managedObjectContext]; 
    NSError *error; 

    dept.departmentName = @"Accounting"; 
    //save more often than normal to see more easily what causes error 
    if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); 

    NSEntityDescription *empEntity = [NSEntityDescription entityForName:@"Employee" 
               inManagedObjectContext:self.managedObjectContext]; 
    emp.firstName = @"Steve"; 
    emp.lastName = @"Smith"; 
    emp.worksIn = dept; 

    if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); 

    emp = [[Employee alloc] initWithEntity:empEntity 
      insertIntoManagedObjectContext:self.managedObjectContext]; 
    emp.firstName = @"Natasha"; 
    emp.lastName = @"Johnson"; 
    emp.worksIn = dept; 

    if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); 

    //all good so far! now will try to delete all employees for this department 
    dept.employees = [NSSet set]; 
    if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); //"Multiple validation errors occurred." 

    //this also produces the same error 
    [[dept mutableSetValueForKey:@"employees"] removeAllObjects]; 
    if (![self.managedObjectContext save:&error]) NSLog(@"\nError: %@", [error localizedDescription]); //"Multiple validation errors occurred." 

La relación employees no es opcional, así que supongo que la eliminación de los empleados del departamento significa que estoy tratando de "huérfanos" de los empleados, es decir, mantener a los empleados en el persistido modelo sin un departamento asociado.

Entonces, creo que mi pregunta original debe volver a redactarse: ¿cuál es la mejor/manera recomendada de eliminar todos los objetos "secundarios" de un "padre" cuando los hijos tienen una relación no opcional con el padre?

Sospecho que la respuesta será "recorrer y borrar los objetos del empleado de a uno por vez".

ACTUALIZACIÓN

De acuerdo con una respuesta y un enlace a la documentación de Apple, yo debería ser capaz de establecer la norma de supresión de "cascada" y luego un código como department.employees = [NSSet set]; funcionará. Sin embargo, esto no funciona en mi proyecto muy simple donde he configurado la regla de eliminación en consecuencia.

Gracias

+1

me pregunto si ha encontrado una solución a ese problema? Estoy teniendo el mismo problema ... para seguir con su ejemplo, tengo un proceso de sincronización en el que intento eliminar a todos los empleados y luego crearlos desde cero (para no complicar demasiado mi sincronización) ... pero actualmente la única manera Conseguí que trabajar fuera eliminar la relación 'a muchos' para ambos lados - iterar a los empleados que llamaban a [managedObjectContext deleteObject: employee] y luego hacer un [[department mutableSetValueForKey: @ "employees"] removeAllObjects]; que simplemente parece estar mal, pero funciona ... – herbert

+0

Nunca me salió el ejemplo de arriba para que funcione. Al final, repetí iterativamente a través de los empleados y los eliminé, como en la respuesta a continuación, acabo de aceptar como la respuesta – stifin

+3

Usted entiende mal la documentación. Cuando ELIMINA el objeto del departamento, la regla de eliminación se aplicará a los objetos del empleado en el conjunto de empleados. Cambiar la relación no eliminará ningún objeto. – Eric

Respuesta

16

Si desea eliminar los elementos empleados para un departamento específico, entonces se podría ejecutar un bucle for-in como por

for (Employees * theEmployee in department.employees) { 
    [self.managedObjectContext deleteObject:[self.managedObjectContext objectWithID:theEmployee.objectID]]; 
} 

continuación, guarde su contexto administrado. SI, por supuesto, eso es lo que quiere, y no eliminar la relación entre los empleados y el departamento; en ese caso, asignar un juego vacío funcionaría.

Variación de arriba:

for (Employee *employeeToDelete in department.employees) { 
    [self.managedObjectContext deleteObject:employeeToDelete]; 
} 
+0

que simplemente establece el puntero del bucle 'theEmployee' en nil, no afectará en absoluto al objeto gestionado. –

+0

Mi mal, editado;) –

+0

actualmente, esta es la técnica que estoy usando solo porque no puedo hacer que la cascada elimine el trabajo ... Excepto que la mía es más simple. Lo he pegado debajo de tu código – stifin

14

Ajuste de la relación de los empleados del departamento a un conjunto vacío, no se eliminarán los empleados, independientemente de la regla de eliminación. Creo que estás malinterpretando la regla de eliminación. De acuerdo con los documentos de Apple: "La regla de eliminación de una relación especifica lo que debería suceder si se intenta eliminar el objeto de origen". Por lo tanto, la conexión en cascada solo tendrá efecto si ELIMINAMOS el departamento.Al establecer la relación con un conjunto vacío, lo único que estamos haciendo es separar a los empleados del departamento, no eliminarlos. Y si esa relación no está configurada como opcional para los empleados, esto causará un error al guardar. Si desea eliminar a los empleados del departamento, puede recorrerlos como se indica más arriba, o establecer la relación entre departamentos en cascada y luego eliminar el departamento.

+0

Gracias: su respuesta llega al origen del asunto y confirma cómo sospecho que funcionan las reglas de eliminación. Creo que si añadieras algún código, se convertiría (y ciertamente debería) en la respuesta preferida. – Benjohn

1

También tuve algo parecido a continuación, pero no funcionó ...

- (BOOL)deleteCollection:(Collection *)collection 
{ 
// Grab the context 
NSManagedObjectContext *context = [self managedObjectContext]; 
NSError *error = nil; 

[collection removeSounds:collection.sounds]; 
[context deleteObject:collection]; 

// Save everything 
if ([context save:&error]) { 
    return YES; 
} 
return NO; 

}

Obviamente la capa de base de datos no puede eliminar los sonidos y luego la colección a la vez. Configuración de la norma de supresión en la relación de 'cascada' muy bien resuelto mi problema y me deja utilizar simplemente:

[context deleteObject:collection]; 

Si desea guardar algunas personas detallada tiempo leyendo a continuación, sólo marcar esto como la respuesta.

Como Fervus se ha dicho anteriormente, este enlace también puede ser útil para los profesionales: Propagate deletes immediately in Core Data

Cuestiones relacionadas