【问题标题】:Why CoreData does not provide class named NSDeleteRequest like NSFetchRequest为什么 CoreData 没有像 NSFetchRequest 那样提供名为 NSDeleteRequest 的类
【发布时间】:2011-10-21 17:24:09
【问题描述】:

我想知道为什么 iPhone 的 CoreData 框架不提供使用 NSPredicate 从组中删除对象的功能。他们提供了使用 NSFetchRequest 获取数据的方法,但我没有找到任何方法或类来使用 NSPredicate 删除组中的对象。例如,我想从客户余额为零的客户表中删除这些对象。我可以在核心数据中使用 for 循环来做到这一点,但我想知道为什么苹果没有提供以这种方式删除对象的方法?

【问题讨论】:

    标签: iphone ios4 core-data iphone-sdk-3.0


    【解决方案1】:

    您应该能够使用NSManagedObjectContextdeleteObject: 方法从数据库中删除对象。同样,如果您从核心数据模型创建了 .h 和 .m 文件,它应该为对象创建了从自身中删除一对多关系对象的方法(类似于 -(void)removeCustomersObject:(Customer *)value-(void)removeCustomers:(NSSet *)value.

    使用此信息,您应该能够设置一个参数来检查余额是否为零,并使用这些方法之一删除对象。一种可能性是偶尔使用获取请求来查找余额为零的所有客户(使用NSPredicate)并从数据库中删除获取的结果。我希望这会有所帮助,并让您知道去哪里。我本来会更详细,但如果没有更多信息,很难给出太多建议。无论如何,这应该为如何缓解您的问题提供一个很好的垫脚石。

    编辑:有两种方法可以从核心数据中删除多个对象。最简单的是假设您有两个实体。一个是父母,我称之为MyDatabase,它将所有孩子保持在一对多的关系中。这些将是您的 Customer 或 Person 对象。你给它起什么名字并不重要,但那些是平衡的对象。对于这个例子,我将只调用类Customer

    如果您为实体生成代码(通过转到您的 xcdatamodeld 文件,选择实体,然后转到 Editor->Create NSManagedObject Subclass),您将看到父实体的类似内容。

    @class Customer;
    @interface MyDatabase : NSManagedObject {
    }
    @property (nonatomic, retain) NSSet *customers;
    

    在您的 .m 文件中,

    @implementation MyDatabase
    @dynamic customers
    
    - (void)addCustomersObject:(Customer *)value {    
        NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
        [self willChangeValueForKey:@"customers" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
        [[self primitiveValueForKey:@"customers"] addObject:value];
        [self didChangeValueForKey:@"customers" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
        [changedObjects release];
    }
    
    - (void)removeCustomersObject:(Customer *)value {
        NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
        [self willChangeValueForKey:@"givenSurveys" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
        [[self primitiveValueForKey:@"customers"] removeObject:value];
        [self didChangeValueForKey:@"customers" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
        [changedObjects release];
    }
    
    - (void)addCustomers:(NSSet *)value {    
        [self willChangeValueForKey:@"customers" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
        [[self primitiveValueForKey:@"customers"] unionSet:value];
        [self didChangeValueForKey:@"customers" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
    }
    
    - (void)removeCustomers:(NSSet *)value {
        [self willChangeValueForKey:@"customers" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
        [[self primitiveValueForKey:@"customers"] minusSet:value];
        [self didChangeValueForKey:@"customers" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
    }
    

    同样,这些是在创建文件时为您创建的,但如果由于某种原因它们不是,您可能没有正确设置关系。

    要删除文件,您需要使用谓词获取上下文。返回的请求是一个NSArray,其中的对象符合条件(余额为 0)。在本例中,我们将只调用该数组objectsToRemove。在这一点上,我们已经准备好尝试两种可能的解决方案了。

    1) 在此,您的核心数据没有子/父实体映射,只有一个实体。在这种情况下,您将使用如上所述的获取请求。然后你会调用类似下面的东西

    for (id myObject in objectsToDelete) {
        [self.managedObjectContext deleteObject:myObject];
    }
    // commit the changes;
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        // handle the error;
    }
    

    这会删除所有对象,然后在完成后保存您的上下文。

    2) 如果你有一个父/子核心数据映射,它会变得更容易。在这种情况下,您只需在获取请求期间调用以下命令

    [myDatabase removeCustomers:[NSSet setWithArray:objectsToDelete]];
    // commit the changes;
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        // handle the error;
    }
    

    第二种方法一次删除所有对象,但确实要求您拥有一个包含Customer 对象的实体。在我看来,这是一种更好的方法,尽管不是必需的,特别是如果您不需要将 Customer 对象分成不同的组。这个Core Data tutorial 概述了经典的部门和员工项目,这是一个非常简单但清晰的示例,说明了如何在核心数据中使用父/子层次结构。

    【讨论】:

    • 你说要删除对象,我首先需要获取它们,然后我需要一个一个地删除它们。但我的观点是我为什么要先获取它们,我只需要删除它们。为什么他们没有提供 NSDeleteRequest 以与 NSPredicare 一起使用?
    • 你不必一一删除。提取可以返回要删除的对象数组。然后你可以说,如果你有一对多的关系,[myDatabase removeCustomers:[NSSet setFromArray:myFetchedResults]],它会一次删除所有的对象。无需循环遍历并一次删除一个
    • 你能用更多的代码解释一下吗?在上面的评论中,您使用了 myDatabase 对象。这个对象属于哪一类?这个 removeCustomers 方法是标准的吗?也就是说,如果它是 person 而不是 customer,那么方法名称将是 removePersons:。不是吗?
    • 这是您的核心数据层次结构的问题。我假设你有一个父类和孩子。实际上,我将更新我上面的答案以包含此内容,因为我认为我会用完空间。此外,您可以更轻松地在那里阅读而不是在评论中阅读
    • 非常感谢这么好的解释。但是正如您所解释的,我的数据库中没有任何子/父层次结构,因此我必须在 for 循环中一一删除这些对象,正如您在上面的代码中所解释的那样。我不要那个。那么为什么苹果会保留这样的架构呢?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 2013-10-16
    • 2011-04-12
    • 1970-01-01
    • 2021-09-07
    相关资源
    最近更新 更多