Core Data基本使用(附两表关联Demo)
前言
对于许多应用来说,需要将本地保存和获取的数据持久化用在其他会话中。从ios3.0开始,Core Data就负责完成这项工作。Core Data是一个非常强大的对象数据库,提供了非常健壮的数据存储和管理功能,和java EE的MyBetis有点类似,都是对数据持久化封装的框架,Core Data是对SQLite的封装,是SQLite的轻量版
特性
- 使用可视化模型编辑器模块化数据对象
- 对象架构变化时自动处理和手动处理间转换的工具
- 在对象间建立关系(一对一、一对多、多对多)
- 在不同的文件和文件格式中保存数据
- 对象特性的有效性验证
- 查询和排序数据
- 数据的延时加载
- 同iOS表视图和集合视图紧密交互
- 通过提交和撤销功能管理相关对象的变化
Demo描述
有两张表,这样既可以学会基础的增删查改,也可以知道多表之间的操作,下面可能比较基础
创建项目
image.png这个我们可以先别选,因为做项目的时候你怎么知道要用Core Data,然后我们自己手动创建一个文件,command+N
image.png
创建成功就会多出一个.xcdatamodeld的文件,这个就是模型文件,注意这不是底层数据库,只是数据库的映射吧,点击这个文件看看
Snip20181016_2.png
点击Add Entity创建两个实体(实体名称首字母必须大写),学生实体和课程实体,学生有三个属性,课程有两个属性,关系是多对多关系,一个学生可以有多门课程,一门课程可以多个学生学习,先看下那个lentstudent这个相当于外键的名称吧,第二个就是关联哪张表,第三个就是逆,即你在关联哪张表的关联名称,也就是说你在Cousre实体关联Student实体的关联名称是lentstudent,那个Inverse是lentcourse,那么你在在Student实体关联Cousre实体的关联名称是lentsourse
选中关系看右边 image.pngto many就是对多咯,你想要多对多就是两张表都设置成to many就多对多了
把这些都搞完了,就要创建实体模型的类了,就相当于plist文件,你要创建一个模型类。
core data创建实体的模型类,xcode会帮你做,直接点就行了,选中
.xcdatamodeld文件,然后看图
image.png
image.png
点完后就会多出这几个实体类,你想用那个实体引用头文件就行
image.png
接下来我们去storyboard上拉四个按钮,简单地修改他的约束,在把他们的单击事件拉到控制器
image.pngimage.png
接下来记住几个Core Data类名
-
NSManagedObjectModel
描述了数据模型的结构信息(被管理的数据模型,数据结构) -
NSPersistentStoreCoordinator
数据持久层和内存对象模型的协助器(添加数据库,设置数据存储的名字,位置,存储方式) -
NSManagedObjectContext
内存中managedObject对象的上下文(管理对象上下文,持久性存储模型对象,处理数据与应用的交互) -
NSFetchRequest
数据请求 -
NSEntityDescription
表格实体结构
首先看下Demo的头文件
image.png首先肯定要有coredata的头文件,你要用什么实体(表)就添加什么实体的这个类
image.png
第一步 创建数据库
这里的数据库是指底层的SQLite,这里写个方法,没有直接帮你创建这个名字的sqlite数据库,我们先创建一个管理上下文的对象
//用来管理上下文的对象
NSManagedObjectContext * _context;
再写创建数据库的方法
//创建数据库
- (void)creatsqlite
{
//1、创建模型对象
//获取模型路径
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
//根据模型文件创建模型对象
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
//2、创建持久化存储助理:数据库
//利用模型对象创建助理对象
NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
//数据库的名称和路径
NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *sqlPath = [docStr stringByAppendingPathComponent:@"sqlite.sqlite"];
NSLog(@"数据库 path = %@", sqlPath);
NSURL *sqlUrl = [NSURL fileURLWithPath:sqlPath];
NSError *error = nil;
//设置数据库相关信息 添加一个持久化存储库并设置存储类型和路径,NSSQLiteStoreType:SQLite作为存储库
[store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:nil error:&error];
if (error) {
NSLog(@"添加数据库失败:%@",error);
} else {
NSLog(@"添加数据库成功");
}
//3、创建上下文 保存信息 操作数据库
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
//关联持久化助理
context.persistentStoreCoordinator = store;
_context = context;
}
这里为什么获取模型文件的时候是momd而不是xcdatamodeld
因为初始化必须依赖.momd文件路径,而.momd文件由.xcdatamodeld文件编译而来
跑一下工程
image.png这个路径就会多出一个叫sqlite的数据库,自己可以根据给出的路径去找下,查看隐藏文件夹快捷键shift+cmmand+.
第二步 插入数据
//增
- (IBAction)insertData {
// 1.根据Entity名称和NSManagedObjectContext获取一个新的继承于NSManagedObject的子类Student
// 2 根据表Course中的键值,给NSManagedObject对象赋值
Course *course1 = [NSEntityDescription
insertNewObjectForEntityForName:@"Course"
inManagedObjectContext:_context];
course1.name = @"iOS";
course1.creatdate = [NSDate date];
Course *course2 = [NSEntityDescription
insertNewObjectForEntityForName:@"Course"
inManagedObjectContext:_context];
course2.name = @"Android";
course2.creatdate = [NSDate date];
// 3 同上操作
Student *student1 = [NSEntityDescription
insertNewObjectForEntityForName:@"Student"
inManagedObjectContext:_context];
student1.name = @"张三";
student1.birthday = [NSDate date];
//student1.lentcourse = course1;
[student1 addLentcourseObject:course1];
Student *student2 = [NSEntityDescription
insertNewObjectForEntityForName:@"Student"
inManagedObjectContext:_context];
student2.name = @"李四";
student2.birthday = [NSDate date];
[student2 addLentcourseObject:course2];
// 4.保存插入的数据
NSError *error = nil;
if ([_context save:&error]) {
NSLog(@"数据插入到数据库成功");
}else{
NSLog(@"数据插入到数据库失败, %@",error);
}
}
-
注意
student1.lentcourse = course1这样写不怎么对,我也是看网上有些教程这样写,类型不对,course1是NSSet类型而student1.lentcourse好像是Course类,所以,我们找下Student+CoreDataProperties.h这个类,他提供了一个方法
-(void)addLentcourseObject:(Course *)value;
这个方法返回才是Course类的
写完这个方法我们再跑下,看下他有没有添加数据进去了,可以用这个软件看下这个数据库
image.png
点击插入
image.png
加进来了
image.png
第三步 查询数据
//查
- (IBAction)queryData {
//1:FectchRequest 抓取请求对象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
//2:设置过滤条件 这里我们查询选了iOS课的学生信息
NSPredicate *pre = [NSPredicate predicateWithFormat:@"ANY lentcourse.name = %@",@"iOS"];
request.predicate = pre;
//3:设置排序
// NSSortDescriptor *height = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:YES];
// request.sortDescriptors = @[height];
//4:执行请求
NSArray *message = [_context executeFetchRequest:request error:nil];
//遍历查询结果
for (Student *student in message) {
NSLog(@"名字:%@,生日:%@",student.name,student.birthday);
}
}
iOS课程是张三在学习
- 注意 那个过滤条件前是要加ANY的,等下下面我会给出那些谓词条件,有些教程没加ANY我也不知道他怎么跑起来的
第四步 删除
//删
- (IBAction)deleteData {
//1:先查询到需要删除的数据(比如这里以删除员工张三的数据为例)
//1.1:FectchRequest 抓取请求对象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
//1.2:设置过滤条件
NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@",@"张三"];
request.predicate = pre;
//1.3执行查询请求
NSArray *message = [_context executeFetchRequest:request error:nil];
//2:执行删除操作
for (Student *student in message) {
[_context deleteObject:student];
}
//3:保存
[_context save:nil];
}
点击删除,张三没了
image.png
第五步 修改
//改
- (IBAction)upDateData {
//1:先查询出需要更新的数据
//1.1:FectchRequest 抓取请求对象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
//1.2:设置过滤条件
NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@",@"李四"];
request.predicate = pre;
//1.3执行查询请求
NSArray *message = [_context executeFetchRequest:request error:nil];
//2:更新数据
for (Student *student in message) {
student.name = @"王五";
}
//3:保存
[_context save:nil];
}
image.png
/* 谓词的条件指令
1.比较运算符 > 、< 、== 、>= 、<= 、!=
例:@"number >= 99"
2.范围运算符:IN 、BETWEEN
例:@"number BETWEEN {1,5}"
@"address IN {'shanghai','nanjing'}"
3.字符串本身:SELF
例:@"SELF == 'APPLE'"
4.字符串相关:BEGINSWITH、ENDSWITH、CONTAINS
例: @"name CONTAIN[cd] 'ang'" //包含某个字符串
@"name BEGINSWITH[c] 'sh'" //以某个字符串开头
@"name ENDSWITH[d] 'ang'" //以某个字符串结束
5.通配符:LIKE
例:@"name LIKE[cd] '*er*'" // *代表通配符,Like也接受[cd].
@"name LIKE[cd] '???er*'"
*注*: 星号 "*" : 代表0个或多个字符
问号 "?" : 代表一个字符
6.正则表达式:MATCHES
例:NSString *regex = @"^A.+e$"; //以A开头,e结尾
@"name MATCHES %@",regex
注:[c]*不区分大小写 , [d]不区分发音符号即没有重音符号, [cd]既不 区分大小写,也不区分发音符号。
7. 合计操作
ANY,SOME:指定下列表达式中的任意元素。比如,ANY children.age < 18。
ALL:指定下列表达式中的所有元素。比如,ALL children.age < 18。
NONE:指定下列表达式中没有的元素。比如,NONE children.age < 18。它在逻辑上等于NOT (ANY ...)。
IN:等于SQL的IN操作,左边的表达必须出现在右边指定的集合中。比如,name IN { 'Ben', 'Melissa', 'Nick' }。
提示:
1. 谓词中的匹配指令关键字通常使用大写字母
2. 谓词中可以使用格式字符串
3. 如果通过对象的key
path指定匹配条件,需要使用%K
*/
因为才看了网上很多文章写出来的,绝对是取其精华的,有些文章比我的还水,有些观点也是我自己的观点,我也是一名菜鸟,希望有错能指出,相互学习
最后附上源码地址:Demo Github地址