美文网首页
CoreData从入门到精通二(增删改查)

CoreData从入门到精通二(增删改查)

作者: Moker_C | 来源:发表于2018-05-04 15:45 被阅读45次

    增:
    新添加一条数据,首先需要创建被添加的数据,使用 NSEntityDesctiption 类的 + (__kindof NSManagedObject *)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context; 方法来创建一个新的 NSManagedObject 对象,参数分别是 entityName 和 managedObjectContext,entityName 也就是实体类的名字,例如,我要插入一条新的 Student 字段,entityName 就是 @”Student”;
    context 是 NSManagedObjectContext对象,新增的实体类对象会添加到对应的 context 上下文对象中。这个方法返回的是一个 NSManagedObject 实例,可以根据具体情况转换成相应的子类

    Student *stu = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.context];
        stu.name = @"kobe";
        stu.age = 20;
        NSError *error;
        [self.context save:&error];
    //如果循环添加多条数据时,将数据都添加完之后再调用[self.context save:&error]方法
    

    调用 save 方法时,可以传入一个 NSError 的指针,如果数据保存出错的话,错误信息会保存到 error 里,这也是 Objective-C 里通常处理错误的方式

    查:
    从数据库中查询数据,会用到三个类:NSFetchRequestNSPredicateNSSortDescriptor,分别说一下这三个类的作用:

    • NSFetchRequest — fetchRequest 代表了一条查询请求,相当于 SQL 中的 SELECT 语句
    • NSPredicate — predicate 翻译过来是谓词的意思,它可以指定一些查询条件,相当于 SQL 中的 WHERE 子句
    • NSSortDescriptor — sortDescriptor 是用来指定排序规则的,相当于 SQL 中的 ORDER BY 子句

    NSFetchRequest 中有两个属性 predicatesortDescriptors,就是用来指定查询的限制条件的。其中 sortDescriptors 是一个 NSSortDescriptor 的数组,也就是可以给一个查询指定多个排序规则,这些排序规则的优先级就是它们在数组中的位置,数组前面的优先级会比后面的高。除此之外,NSFetchRequest 还有下面这些属性

    • fetchLimit — 指定结果集中数据的最大条目数,相当于 SQL 中的 LIMIT 子句
    • fetchOffset — 指定查询的偏移量,默认为 0
    • fetchBatchSize — 指定批处理查询的大小,设置了这个属性后,查询的结果集会分批返回
    • entityName/entity — 指定查询的数据表,相当于 SQL 中的 FROM 语句
    • propertiesToGroupBy — 指定分组规则,相当于 SQL 中的 GROUP BY 子句
    • propertiesToFetch — 指定要查询的字段,默认会查询全部字段

    配置好 NSFetchRequest 对象后,需要调用 NSManagedObjectContext- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error; 来执行查询,返回的数组就是查询出的结果集

    //一条查询请求,相当于 SQL 中的 SELECT 语句
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        //实体
        NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.context];
        [fetchRequest setEntity:entityDescription];
        //还可以写成 NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Student"]; 或 NSFetchRequest *fetchRequest = [Student fetchRequest];
        //查询条件
        fetchRequest.predicate = [NSPredicate predicateWithFormat:@"age > %@", @(20)];
        //排序
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
        [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
        NSError *error;
        NSArray <Student *> *fetchObjects = [self.context executeFetchRequest:fetchRequest error:&error];
        if (!fetchObjects.count) {
            NSLog(@"没有数据");
        }else {
            NSLog(@"%@",fetchObjects);
        }
    

    删:
    将上一步查询到的结果,调用 NSManagedObjectContext 的 - (void)deleteObject:(NSManagedObject *)object; 方法来删除一个条目。例如,将上面查询出来的 students 全部删除,可以这么写:

    for (Student *stu in fetchObjects) {
            [self.context deleteObject:stu];
        }
        NSError *error;
        [self.context save:&error];
    
    //NSBatchDeleteRequest 批量删除
    //    NSBatchDeleteRequest 的用法和 NSBatchUpdateRequest 很相似,不同的是 NSBatchDeleteRequest 需要指定 fetchRequest 属性来进行删除;而且它是 iOS 9 才添加进来的,和 NSBatchUpdateRequest 的适用范围不一样
        NSFetchRequest *deleteFetch = [Student fetchRequest];
        
        deleteFetch.predicate = [NSPredicate predicateWithFormat:@"age == %@", @(20)];
        
        NSBatchDeleteRequest *deleteRequest = [[NSBatchDeleteRequest alloc] initWithFetchRequest:deleteFetch];
        deleteRequest.resultType = NSBatchDeleteResultTypeObjectIDs;
        
        NSBatchDeleteResult *deleteResult = [self.context executeRequest:deleteRequest error:nil];
        NSArray<NSManagedObjectID *> *deletedObjectIDs = deleteResult.result;
        
        NSDictionary *deletedDict = @{NSDeletedObjectsKey : deletedObjectIDs};
        [NSManagedObjectContext mergeChangesFromRemoteContextSave:deletedDict intoContexts:@[self.context]];
    

    改:
    将之前查询的到的数据进行如下操作可进行修改:

    for (Student *student in fetchObjects) {
            student.name = @"newName";
        }
        [self.context save:nil];
        //批量更新,将所有name更改为Tom,用到的是集合类型中的 KVC 特性
        [students setValue:@"Tom" forKeyPath:@"name"];
    
    //NSBatchUpdateRequest 批量更新
    //    NSBatchUpdateRequest 是在 iOS 8, macOS 10.10 之后新添加的 API,它是专门用来进行批量更新的。因为用上面那种方式批量更新的话,会存在一个问题,就是更新前需要将要更新的数据,查询出来,加载到内存中;这在数据量非常大的时候,假如说要更新十万条数据,就比较麻烦了,因为对于手机这种内存比较小的设备,直接加载这么多数据到内存里显然是不可能的。解决办法就是每次只查询出读取一小部分数据到内存中,然后对其进行更新,更新完之后,再更新下一批,就这样分批来处理。但这显然不是高效的解决方案。
    //
    //    于是就有了 NSBatchUpdateRequest 这个 API。它的工作原理是不加载到内存里,而是直接对本地数据库中数据进行更新。这就避免了内存不足的问题;但同时,由于是直接更新数据库,所以内存中的 NSManagedObjectContext 不会知道数据库的变化,解决办法是调用 NSManagedObjectContext 的 + (void)mergeChangesFromRemoteContextSave:(NSDictionary*)changeNotificationData intoContexts:(NSArray<NSManagedObjectContext*> *)contexts;方法来告诉 context,有哪些数据更新了。
        // 根据 entity 创建
        NSBatchUpdateRequest *updateRequest = [[NSBatchUpdateRequest alloc] initWithEntity:[Student entity]];
        // 根据 entityName 创建
    //    NSBatchUpdateRequest *updateRequest = [[NSBatchUpdateRequest alloc] initWithEntityName:@"Student"];
        updateRequest.predicate = [NSPredicate predicateWithFormat:@"studentAge == %@", @(20)];
    //    propertiesToUpdate 属性是一个字典,用它来指定需要更新的字段,字典里的 key 就是要更新的字段名,value 就是要设置的新值。因为 Objective-C 字典里只能存储对象类型,所以如果字段基本数据类型的的话,需要转换成 NSNumber 对象
        updateRequest.propertiesToUpdate = @{@"name" : @"anotherName"};
    
    updateRequest.resultType = NSUpdatedObjectIDsResultType;
        NSBatchUpdateResult *updateResult = [self.context executeRequest:updateRequest error:nil];
        NSArray<NSManagedObjectID *> *objectIDs = updateResult.result;
        NSLog(@"ids===%@",objectIDs);
    

    相关文章

      网友评论

          本文标题:CoreData从入门到精通二(增删改查)

          本文链接:https://www.haomeiwen.com/subject/pkvdrftx.html