2016-01-06 2 views
0

J'ai un modèle de données de base avec deux entités, 'Parent' et 'Enfant'. Le parent a une relation to-many avec l'enfant et l'enfant a une relation to-one avec le parent. Je souhaite empêcher les modifications de la relation parent dans l'enfant une fois que son parent a été défini. La suppression de l'enfant, cependant, devrait être autorisée.interdire la modification de la relation de données de base, mais éventuellement permettre la suppression de l'enfant

de setParent de l'enfant ressemble à ceci:

- (void)setParent:(Parent *)parent { 
    if (self.parent) return; 
    [self willChangeValueForKey:@"parent"]; 
    [self setPrimitiveValue:parent forKey:@"parent"]; 
    [self didChangeValueForKey:@"parent"]; 
    } 

Maintenant, cela empêche le changement du parent une fois qu'il est défini, mais en même temps, il empêchera la suppression de l'enfant, parce que setParent se revisité deux fois pendant la suppression pour définir le parent à zéro.

La première fois que setParent est appelé pendant la suppression, self.isDeleted a la valeur true. Donc je peux réagir à cette situation. Mais setParent est encore appelé pendant la suppression, et cette fois self.isDeleted est faux, et je ne sais pas comment savoir si quelqu'un essaie de modifier la relation parent ou si une suppression est en cours.

Je travaille avec MagicalRecord 2.30 et l'appel de suppression ressemble à ceci:

[MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext)  { 

    [sut MR_inContext:localContext]; 
    [sut MR_deleteEntityInContext:localContext]; 
}]; 

Je l'ai regardé partout pour trouver quelques informations au sujet de ces appels setter au cours de suppression, mais pas de chance. Donc toute aide serait appréciée. J'ai mis quelques NSLogs dans mon code pour documenter ce qui se passait. La suppression fonctionne réellement avec ce code, mais je n'ai aucune idée de ce que tous ces appels sont. Voici le code correspondant:

- (BOOL) MR_deleteEntityInContext:(NSManagedObjectContext *)context { 
    NSLog(@"|"); 
    NSLog(@"|"); 
    NSLog(@"----------------------------------"); 
    NSLog(@"| ***** starting delete... ***** |"); 
    NSLog(@"----------------------------------"); 
    NSLog(@"|"); 
    NSLog(@"|"); 
    return [super MR_deleteEntityInContext:context]; 
} 

- (void)setParent:(Parent *)parent { 
    NSLog(@"|"); 
    NSLog(@"--------------------------------------------------------------------------"); 
    NSLog(@"setParent has been called with parameter <%p>", parent); 
    NSLog(@"       self.parent is: %p", self.parent); 
    NSLog(@"self.isDeleted is: %hhd", self.isDeleted); 
    NSLog(@"   self.moc: %@", self.managedObjectContext); 
    NSLog(@"--------------------------------------------------------------------------"); 
    NSLog(@"|"); 
    if (!self.isDeleted && self.parent) return; 
    [self willChangeValueForKey:@"parent"]; 
    [self setPrimitiveValue:parent forKey:@"parent"]; 
    [self didChangeValueForKey:@"parent"]; 
} 

Il produit la sortie suivante:

---------------------------------- 
| ***** starting delete... ***** | 
---------------------------------- 
| 
| 
| 
-------------------------------------------------------------------------- 
setParent has been called with parameter <0x0> 
          self.parent is: 0x6080000a9cc0 
self.isDeleted is: 1 
      self.moc: <NSManagedObjectContext: 0x6000001c05a0> 
-------------------------------------------------------------------------- 
| 
| 
-------------------------------------------------------------------------- 
setParent has been called with parameter <0x0> 
          self.parent is: 0x6080000aa080 
self.isDeleted is: 0 
      self.moc: <NSManagedObjectContext: 0x6080001c0a50> 
-------------------------------------------------------------------------- 
| 
| 
-------------------------------------------------------------------------- 
setParent has been called with parameter <0x0> 
          self.parent is: 0x6080000aa080 
self.isDeleted is: 1 
      self.moc: <NSManagedObjectContext: 0x6080001c0a50> 
-------------------------------------------------------------------------- 
| 
+0

Si vous définissez 'parent' à' nil' lorsque 'self.isDeleted' est vrai, vous pouvez être certain que le second appel ne fait pas partie de la suppression. Sauf si vous n'avez pas de mises à jour synchronisées de votre modèle, alors vous êtes foutu. Mais alors tu es foutu quand même. – Avi

+0

@Avi - merci. Je laisse donc l'appel de setter de delete passer et attend que le parent soit mis à zéro. Mais ce n'est pas le cas. Le test fonctionne de cette façon, mais que se passe-t-il ??? – donnerluetjen

+0

Enregistrez 'self.parent' après avoir défini la valeur.Si vous regardez, vous voyez que le moc change entre le premier et le second appel. Je suppose que le premier est un contexte d'enfant de la seconde. Après le 3ème appel, où le moc est le même que le second, et 'isDeleted == 1', vous devriez trouver que' parent' est nul. – Avi

Répondre

0

Voici ce que j'ai trouvé. J'ai changé un peu le code ci-dessus pour enregistrer également la relation inverse.

- (void)setParent:(Parent *)parent { 
    NSLog(@" "); 
    NSLog(@"--------------------------------------------------------------------------"); 
    NSLog(@"| setParent has been called with parameter <%p>", parent); 
    NSLog(@"|         self is: %p", self); 
    NSLog(@"|       self.parent is: %p", self.parent); 
    NSLog(@"|    parent.children contains: %p", [Parent MR_findFirstInContext:self.managedObjectContext].children.allObjects.firstObject); 
    NSLog(@"| self.isDeleted is: %hhd", self.isDeleted); 
    NSLog(@" "); 
    if (!self.isDeleted && self.parent) return; 
    if (self.isDeleted) [self setPrimitiveValue:nil forKey:@"parent"]; 
    [self willChangeValueForKey:@"parent"]; 
    [self setPrimitiveValue:parent forKey:@"parent"]; 
    [self didChangeValueForKey:@"parent"]; 
    NSLog(@"|- after setting the parent ..."); 
    NSLog(@"|-        self is: %p", self); 
    NSLog(@"|-       self.parent is: %p", self.parent); 
    NSLog(@"|-    parent.children contains: %p", [Parent MR_findFirstInContext:self.managedObjectContext].children.allObjects.firstObject); 
    NSLog(@"--------------------------------------------------------------------------"); 
} 

Lorsque je supprime l'enfant ce qui suit est enregistré:

---------------------------------- 
| ***** starting delete... ***** | 
---------------------------------- 
| 
| 

-------------------------------------------------------------------------- 
| setParent has been called with parameter <0x0> 
|         self is: 0x6000000a79e0 
|       self.parent is: 0x6000000a7a40 
|    parent.children contains: 0x6000000a79e0 
| self.isDeleted is: 1 

|- after setting the parent ... 
|-        self is: 0x6000000a79e0 
|-       self.parent is: 0x0 
|-    parent.children contains: 0x6000000a79e0 
-------------------------------------------------------------------------- 

-------------------------------------------------------------------------- 
| setParent has been called with parameter <0x0> 
|         self is: 0x6080000a8100 
|       self.parent is: 0x6080000a8160 
|    parent.children contains: 0x0 
| self.isDeleted is: 0 


-------------------------------------------------------------------------- 
| setParent has been called with parameter <0x0> 
|         self is: 0x6080000a8100 
|       self.parent is: 0x6080000a8160 
|    parent.children contains: 0x0 
| self.isDeleted is: 1 

|- after setting the parent ... 
|-        self is: 0x6080000a8100 
|-       self.parent is: 0x0 
|-    parent.children contains: 0x0 
-------------------------------------------------------------------------- 

Ainsi, la première et la troisième fois que le compositeur est appelé durant l'effacement, isDeleted est vrai. Mais sur le deuxième appel du setter isDeleted est faux. Si je teste la relation inverse à ce stade, je vois qu'il a déjà été supprimé. Ce test est assez bon pour moi. Il permet au cycle de suppression de passer à travers, et en même temps permet de lancer le setter si la relation n'a pas été définie du tout.

0

Vous pouvez définir parent-nil si isDeleted est true, comme le suggère @Avi.