如何以某种通用方式删除有序对多 CoreData 关系中的对象?

Posted

技术标签:

【中文标题】如何以某种通用方式删除有序对多 CoreData 关系中的对象?【英文标题】:How do I remove objects in an ordered to-many CoreData relationship in some generic way? 【发布时间】:2015-11-19 06:59:12 【问题描述】:

我有一个联系人实体,它与另一个实体的电子邮件地址、电话有一对多的关系。

这种关系(自然称为“电子邮件,电话”)也是有序的,因此我可以在表格视图中显示联系人的电子邮件地址列表,并允许用户删除或修改每一个。据我所知,需要订购它们,以便我可以知道哪个被删除/修改:例如,如果用户点击第 1 行中的删除按钮,则应从关系中删除第二个电子邮件地址。没有被命令,我不知道该删除哪一个。

在生成 NSManagedObject 子类时,我在该类上获得了一个 NSOrderedSet 属性,CoreData 在 .h 文件中提供了一些访问器:

@interface Contact (CoreDataGeneratedAccessors)
- (void)insertObject:(PLEmail *)value inEmailsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromEmailsAtIndex:(NSUInteger)idx;
- (void)insertEmails:(NSArray<PLEmail *> *)value atIndexes:(NSIndexSet *)indexes;
- (void)removeEmailsAtIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectInEmailsAtIndex:(NSUInteger)idx withObject:(PLEmail *)value;
- (void)replaceEmailsAtIndexes:(NSIndexSet *)indexes withEmails:(NSArray<PLEmail *> *)values;
- (void)addEmailsObject:(PLEmail *)value;
- (void)removeEmailsObject:(PLEmail *)value;
- (void)addEmails:(NSOrderedSet<PLEmail *> *)values;
- (void)removeEmails:(NSOrderedSet<PLEmail *> *)values;

- (void)insertObject:(PLTelephone *)value inTelephonesAtIndex:(NSUInteger)idx;
- (void)removeObjectFromTelephonesAtIndex:(NSUInteger)idx;
- (void)insertTelephones:(NSArray<PLTelephone *> *)value atIndexes:(NSIndexSet *)indexes;
- (void)removeTelephonesAtIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectInTelephonesAtIndex:(NSUInteger)idx withObject:(PLTelephone *)value;
- (void)replaceTelephonesAtIndexes:(NSIndexSet *)indexes withTelephones:(NSArray<PLTelephone *> *)values;
- (void)addTelephonesObject:(PLTelephone *)value;
- (void)removeTelephonesObject:(PLTelephone *)value;
- (void)addTelephones:(NSOrderedSet<PLTelephone *> *)values;
- (void)removeTelephones:(NSOrderedSet<PLTelephone *> *)values;
@end

我的问题是有什么办法可以使这段代码通用,所以应该删除isKindOfClass检查:

NSArray *nestedArray = [orderedSet array];
    id nestedObject = [nestedArray objectAtIndex:indexPath.row];
    if ([nestedObject isKindOfClass:[PLEmail class]]) 
        PLEmail *email = (PLEmail *)nestedObject;
        [email MR_deleteEntity];
        [self.contact removeEmailsObject:email];
    
    else if ([nestedObject isKindOfClass:[PLTelephone class]]) 
        PLTelephone *telePhone = (PLTelephone *)nestedObject;
        [email MR_deleteEntity];
        [self.contact removeTelephonesObject:telePhone];
    

【问题讨论】:

您不需要订购型号。相反,只需订购您的数据源。但那是另一回事了。 如果MR_deleteEntity删除了对象,删除规则为null,则该对象自动从联系人中删除。 删除规则无效,但它只是使对象为零,而不是删除.. 有序集中的对象可以为零吗? @Willeke 在有序集中没有对象不能为 nil。 【参考方案1】:

如果您有互惠关系(如推荐的那样),您可以将电子邮件或电话实体上的联系关系设为 nil。这也会从联系人列表中删除该实体。

处理多重关系的示例代码

- (void)removeRelationship:(NSString *)relationshipKeyPath fromEntity:(NSManagedObject *)entity 
    [entity setValue:nil forKeyPath:relationshipKeyPath];

你会这样使用它:

[self removeRelationship:@"contact" fromEntity:unknownRelationshipForContact];

【讨论】:

“电子邮件或电话”实体与许多其他实体的互惠关系与“建筑物或财产等”实体一样。在那种情况下,我如何从联系人、建筑物、财产等的哪个实体中找到我必须使电子邮件为零? 我认为你根本无法在不了解任何上下文的情况下逃脱。你必须知道你在一方或另一方切断了哪种关系。最初的问题没有说明双方涉及多种关系。 但是,您可以有一个通用的removeContact: 方法,它不关心接收者是email 还是telephone 实体。然后对removeBuilding:等做同样的事情。 还是一样,然后会检查建筑物或联系人,顺便说一句,它不是通用的.. 实际上,您可以通过传入要切断的关系的 keyPath 使其更通用。然后您可以使用NSManagedObject 的原始方法来处理它。但是,这会导致代码脆弱,并且仍然需要在某处的 some 上下文。

以上是关于如何以某种通用方式删除有序对多 CoreData 关系中的对象?的主要内容,如果未能解决你的问题,请参考以下文章

CoreData 多对多关系插入和删除操作

核心数据(添加唯一约束后):注释:修复丢失的删除传播以实现对多关系

保存循环删除多对多CoreData关系的一端

CoreData:如何建模循环多对多关系

如何使用带有插入/删除的 Core Data(或 SQL)维护有序表?

以编程方式在运行时删除或添加属性到CoreData