CoreData 从入门到精通 二 数据的增删改查
2016-12-09 16:06
423 查看
在上篇博客中,讲了数据模型和 CoreData 栈的创建,那下一步就是对数据的操作了。和数据库一样,CoreData 里的操作也无非是增删改查。下面我们将逐步讲解在 CoreData 中进行增删改查的方式。
调用
NSFetchRequest — fetchRequest 代表了一条查询请求,相当于 SQL 中的 SELECT 语句
NSPredicate — predicate 翻译过来是谓词的意思,它可以指定一些查询条件,相当于 SQL 中的 WHERE 子句,有关 NSPredicate 的用法,可以看我之前写过的一篇文章:使用 NSPredicate 进行数据库查询
NSSortDescriptor — sortDescriptor 是用来指定排序规则的,相当于 SQL 中的 ORDER BY 子句
在
fetchLimit — 指定结果集中数据的最大条目数,相当于 SQL 中的 LIMIT 子句
fetchOffset — 指定查询的偏移量,默认为 0
fetchBatchSize — 指定批处理查询的大小,设置了这个属性后,查询的结果集会分批返回
entityName/entity — 指定查询的数据表,相当于 SQL 中的 FROM 语句
propertiesToGroupBy — 指定分组规则,相当于 SQL 中的 GROUP BY 子句
propertiesToFetch — 指定要查询的字段,默认会查询全部字段
配置好
Xcode 中预置了用来创建 fetchRequest 的code snippet,键入
创建出来的代码是这样子的:
基本上常用到的代码都在这里了。当然我们也可以自己来手写出来,下面就是一个最简单的查询语句:
除了这种批量更新的方式,还有下面将要讲的
于是就有了
下面来看一下
创建
predicate
propertiesToUpdate
resultType
好了,CoreData 中的增删改查就讲完了,下篇文章将会介绍 CoreData Model 中的 relationships 实现多表关联的用法。
基本的增删改查
插入条目
先来看一下插入条目的方式,在插入之前,我们需要先创建要插入的数据, 使用NSEntityDesctiption类的
+ (__kindof NSManagedObject *)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context;方法来创建一个新的
NSManagedObject对象,入参分别是
entityName和
managedObjectContext,
entityName也就是实体类的名字,例如,我要插入一条新的
Student字段,
entityName就是 @”Student”;
context是
NSManagedObjectContext对象,新增的实体类对象会添加到对应的
context上下文对象中。这个方法返回的是一个
NSManagedObject实例,可以根据具体情况转换成相应的子类:
Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.context]; student.studentName = @"小明"; student.studentId = 1; student.studentAge = 20; NSError *error; [self.context save:&error];
调用
save方法时,可以传入一个
NSError的指针,如果数据保存出错的话,错误信息会保存到
error里,这也是
Objective-C里通常处理错误的方式。
查询条目
从数据库中查询数据,会用到三个类:NSFetchRequest,
NSPredicate,
NSSortDescriptor,分别说一下这三个类的作用:
NSFetchRequest — fetchRequest 代表了一条查询请求,相当于 SQL 中的 SELECT 语句
NSPredicate — predicate 翻译过来是谓词的意思,它可以指定一些查询条件,相当于 SQL 中的 WHERE 子句,有关 NSPredicate 的用法,可以看我之前写过的一篇文章:使用 NSPredicate 进行数据库查询
NSSortDescriptor — sortDescriptor 是用来指定排序规则的,相当于 SQL 中的 ORDER BY 子句
在
NSFetchRequest中有两个属性
predicate、
sortDescriptors,就是用来指定查询的限制条件的。其中
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;来执行查询,返回的数组就是查询出的结果集。
Xcode 中预置了用来创建 fetchRequest 的code snippet,键入
fetch,就会出现相应的提示:
创建出来的代码是这样子的:
基本上常用到的代码都在这里了。当然我们也可以自己来手写出来,下面就是一个最简单的查询语句:
NSFetchRequest *fetchRequest = [Student fetchRequest]; // 自动创建的 NSManagedObject 子类里会生成相应的 fetchRequest 方法 // 也可以使用这种方式:[NSFetchRequest fetchRequestWithEntityName:@"Student"]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"studentAge > %@", @(20)]; NSArray<NSSortDescriptor *> *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"studentName" ascending:YES]]; fetchRequest.sortDescriptors = sortDescriptors; // NSArray<Student *> *students = [self.context executeFetchRequest:fetchRequest error:nil];
删除条目
简单的删除条目还是比较简单的,在上一步里查询出来后,只需调用NSManagedObjectContext的
- (void)deleteObject:(NSManagedObject *)object;方法来删除一个条目。例如,将上面查询出来的
students全部删除,可以这么写:
for (Student *student in students) { [self.context deleteObject:student]; } [self.context save:nil]; // 最后不要忘了调用 save 使操作生效。
更新条目
还是在查询出的students数组的基础上,如果要更新里面的字段,可以遍历这个数组,依次修改数组里元素的字段:
for (Student *student in students) { student.studentName = @"newName"; } [self.context save:nil];
增删改查进阶
批量插入
简单的批量插入和插入单条数据一样,只是在所有的数据都插入只有才调用[context save];来保存。下面是简单的示例代码:
for (NSUInteger i = 0; i < 1000; i++) { Student *newStudent = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.context]; int16_t stuId = arc4random_uniform(9999); newStudent.studentName = [NSString stringWithFormat:@"student-%d", stuId]; newStudent.studentId = stuId; newStudent.studentAge = arc4random_uniform(10) + 10; } [self.context save:nil];
批量更新
这里讲的批量更新方式,用到的是集合类型中的 KVC 特性。这是什么呢?就是在NSArray这样的集合类型里,可以调用它的
[setValue: forKeyPath:]方法来更新这个数组中所有元素所对应的 keypath。例如想要将上面查询出来的
students数组里所有元素的
studentName属性都修改成
@"anotherName",就可以这么来写:
[students setValue:@"anotherName" forKeyPath:@"studentName"];
除了这种批量更新的方式,还有下面将要讲的
NSBatchUpdateRequest也可以进行批量更新,不妨接着往下看。
NSBatchUpdateRequest 批量更新
NSBatchUpdateRequest是在 iOS 8, macOS 10.10 之后新添加的 API,它是专门用来进行批量更新的。因为用上面那种方式批量更新的话,会存在一个问题,就是更新前需要将要更新的数据,查询出来,加载到内存中;这在数据量非常大的时候,假如说要更新十万条数据,就比较麻烦了,因为对于手机这种内存比较小的设备,直接加载这么多数据到内存里显然是不可能的。解决办法就是每次只查询出读取一小部分数据到内存中,然后对其进行更新,更新完之后,再更新下一批,就这样分批来处理。但这显然不是高效的解决方案。
于是就有了
NSBatchUpdateRequest这个 API。它的工作原理是不加载到内存里,而是直接对本地数据库中数据进行更新。这就避免了内存不足的问题;但同时,由于是直接更新数据库,所以内存中的
NSManagedObjectContext不会知道数据库的变化,解决办法是调用
NSManagedObjectContext的
+ (void)mergeChangesFromRemoteContextSave:(NSDictionary*)changeNotificationData intoContexts:(NSArray<NSManagedObjectContext*> *)contexts;方法来告诉 context,有哪些数据更新了。
下面来看一下
NSBatchUpdateRequest的用法。
创建
// 根据 entity 创建 NSBatchUpdateRequest *updateRequest = [[NSBatchRequest alloc] initWithEntity:[Student entity]]; // 根据 entityName 创建 NSBatchUpdateRequest *updateRequest = [[NSBatchUpdateRequest alloc] initWithEntityName:@"Student"];
predicate
NSBatchUpdateRequest的
predicate用来指定更新条件,例如这里指定更新 studentAge 等于 20 的学生
updateRequest.predicate = [NSPredicate predicateWithFormat:@"studentAge == %@", @(20)];
propertiesToUpdate
propertiesToUpdate属性是一个字典,用它来指定需要更新的字段,字典里的 key 就是要更新的字段名,value 就是要设置的新值。因为 Objective-C 字典里只能存储对象类型,所以如果字段基本数据类型的的话,需要转换成
NSNumber对象。
updateRequest.propertiesToUpdate = @{@"studentName" : @"anotherName"};
resultType
resultType属性是
NSBatchUpdateRequestResultType类型的枚举,用来指定返回的数据类型。这个枚举有三个成员:
NSStatusOnlyResultType— 返回 BOOL 结果,表示更新是否执行成功
NSUpdatedObjectIDsResultType— 返回更新成功的对象的 ID,是 NSArray\
NSBatchDeleteRequest 批量删除
NSBatchDeleteRequest的用法和
NSBatchUpdateRequest很相似,不同的是
NSBatchDeleteRequest需要指定
fetchRequest属性来进行删除;而且它是 iOS 9 才添加进来的,和
NSBatchUpdateRequest的适用范围不一样,下面看一下示例代码:
NSFetchRequest *deleteFetch = [Student fetchRequest]; deleteFetch.predicate = [NSPredicate predicateWithFormat:@"studentAge == %@", @(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]];
好了,CoreData 中的增删改查就讲完了,下篇文章将会介绍 CoreData Model 中的 relationships 实现多表关联的用法。
相关文章推荐
- CoreData 从入门到精通 (一) 数据模型 + CoreData 栈的创建
- CoreData 从入门到精通 (一) 数据模型 + CoreData 栈的创建
- CoreData 从入门到精通 二 数据的增删改查
- 源码-PL/SQL从入门到精通-第六章-查询数据表-Part 3
- CoreData 入门使用 增删改查 swift
- 大数据应用之:MongoDB从入门到精通你不得不知的21个为什么?
- 大数据应用之:MongoDB从入门到精通你不得不知的21个为什么?
- 基础增删改查-NHibernate入门到精通系列3
- 源码-PL/SQL从入门到精通-第六章-查询数据表-Part 1
- 【Java入门到精通】Java 4类8种数据类型
- CoreData增删改查简单操作及多线程添加数据
- CoreData的简单使用(二)数据的增删改查,轻量级的版本迁移
- MySoft.Data从入门到精通系列(四)【数据插入】
- salesforce 零基础开发入门学习(六)简单的数据增删改查页面的构建
- 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目 (12)程序与数据备份
- Mysql入门到精通数据表的操作
- sql索引从入门到精通(十亿行数据测试报告)
- Android中数据共享机制的实现——ContentProvider的应用从入门到精通
- CoreData的使用入门到精通
- sql入门基本语法语句数据的操作(增删改查)