core data 入门(2)多对多映射与常见的开发注意事项

          首先需要注意的一点是,当你每次数据库表的结构发生变化的时候,需要先到原先创建该数据库的沙盒或者文件夹中手动删除对应的数据库文件,否则,当你再次打开数据库连接的时候,会因为表的数据结构不一样而打开失败。

          本次使用两个实体类person与book,他们是多对多的映射关系,他们对应的添加实体如下图所示



                                                       图1、这是Book的实体创建图(注意图上鼠标所点的 to many 属性)




                                                                          图2、这是Person的实体创建图


按上一篇转载的博文core data 入门所示,按步骤由系统创建生成对应的实体类,他们的代码展示分别如下:

//  Book.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Person;
@interface Book : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * price;
@property (nonatomic, retain) NSString * author;
@property (nonatomic, retain) NSSet *persons;
@end
@interface Book (CoreDataGeneratedAccessors)
- (void)addPersonsObject:(Person *)value;
- (void)removePersonsObject:(Person *)value;
- (void)addPersons:(NSSet *)values;
- (void)removePersons:(NSSet *)values;


@end


//  Book.m
//  CoreData演练
#import "Book.h"
#import "Person.h"

@implementation Book
@dynamic name;
@dynamic price;
@dynamic author;
@dynamic persons;

@end


//
//  Person.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Book;
@interface Person : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * age;
@property (nonatomic, retain) NSString * phoneNo;
@property (nonatomic, retain) NSData * image;//(blob类型,用于存放图片)
@property (nonatomic, retain) NSSet *books;
@end

@interface Person (CoreDataGeneratedAccessors)

- (void)addBooksObject:(Book *)value;
- (void)removeBooksObject:(Book *)value;
- (void)addBooks:(NSSet *)values;
- (void)removeBooks:(NSSet *)values;

@end



//  Person.m


#import "Person.h"
#import "Book.h
@implementation Person


@dynamic name;
@dynamic age;
@dynamic phoneNo;
@dynamic image;
@dynamic books;


@end


前期准备工作完毕,接下来在controller中定义一个内部变量 NSManagedObjectContext  *_context

@interface ViewController ()
{
    // CoreData数据操作的上下文,负责所有的数据操作,类似于SQLite的数据库连接句柄
    NSManagedObjectContext *_context;
}


打开数据库连接


/**
 *  打开数据库
 */
- (void)openDB
{
     ** Core Data的操作方式
     1. 将所有定义好的数据模型文件合并成为一个数据模型(NSManagedObjectModel)
        建立起针对实体对应的数据表的SQL语句,以便创建数据表
     2. 用数据模型来创建持久化存储调度,此时就具备了创建表的能力
     3. 为存储调度添加持久化的数据存储(SQLite数据库),如果没有,新建并创建数据表
        如果已经存在,直接打开数据库。
     
        在打开数据库之后,会判断实体当前的结构与数据表的描述结构是否一致,如果不一致,会提示打开失败!
     */
    // 创建数据库
    // 1. 实例化数据模型(将所有定义的模型都加载进来)
    // merge——合并
    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    
    // 2. 实例化持久化存储调度,要建立起桥梁,需要模型
    NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    
    // 3. 添加一个持久化的数据库到存储调度
    // 3.1 建立数据库保存在沙盒的URL
    NSArray *docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *path = [docs[0] stringByAppendingPathComponent:@"my.db"];
    NSURL *url = [NSURL fileURLWithPath:path];
    
    // 3.2 打开或者新建数据库文件
    // 如果文件不存在,则新建之后打开
    // 否者直接打开数据库
    NSError *error = nil;
    [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
    
    if (error) {
        NSLog(@"打开数据库出错 - %@", error.localizedDescription);
    } else {
        NSLog(@"打开数据库成功!");
        
        _context = [[NSManagedObjectContext alloc] init];
        
        _context.persistentStoreCoordinator = store;
    }
}



新增数据

/**
 新增个人记录
 */
- (void)addPerson
{
    /**
     回顾SQL新增记录的过程
     
     1. 拼接一个INSERT的SQL语句
     2. 执行SQL
     */
    // 1. 实例化并让context“准备”将一条个人记录增加到数据库
    Person *p = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:_context];
    
    // 2. 设置个人信息
    p.name = @"张老头";
    p.age = @10;
    p.phoneNo = @"100";
    p.image = UIImagePNGRepresentation([UIImage imageNamed:@"头像1"]);
    
    // 3. 新增书,实例化并通知上下文准备加书
    Book *b = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:_context];
    b.name = @"太极真经";
    b.price = @20000.99;
    b.author = @"太极忽悠";
    
    Book *b2 = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:_context];
    b2.name = @"一阳神功";
    b2.price = @0.99;
    b2.author = @"老忽悠";


    NSSet *bookSet = [NSSet setWithObjects:b, b2, nil];
    p.books = bookSet;
    
    // 3. 保存(让context保存当前的修改)
    if ([_context save:nil]) {
        NSLog(@"新增成功");
    } else {
        NSLog(@"新增失败");
    }
}


查询记录,注意在coredata的查询中条件使用谓词nspredicate来进行的,以及这些查询条件与sql语句的异同点,查询时的懒加载


- (void)allPersons
{
    // 1. 实例化一个查询(Fetch)请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
    
    // 3. 条件查询,通过谓词来实现的
//    request.predicate = [NSPredicate predicateWithFormat:@"age < 60 && name LIKE '*五'"];
    // 在谓词中CONTAINS类似于数据库的 LIKE '%王%'
//    request.predicate = [NSPredicate predicateWithFormat:@"phoneNo CONTAINS '1'"];
    // 如果要通过key path查询字段,需要使用%K
//    request.predicate = [NSPredicate predicateWithFormat:@"%K CONTAINS '1'", @"phoneNo"];
    // 直接查询字表中的条件
    
    // 2. 让_context执行查询数据
    NSArray *array = [_context executeFetchRequest:request error:nil];
    
    for (Person *p in array) {
        NSLog(@"%@ %@ %@", p.name, p.age, p.phoneNo);
        
        // 在CoreData中,查询是懒加载的,例如下面的book Book *b in p.books是因为被使用到了才查询,如果屏蔽掉这个循环输出操作,将不会查询Book表中的内容
        // 在CoreData本身的SQL查询中,是不使用JOIN的,不需要外键
        // 这种方式的优点是:内存占用相对较小,但是磁盘读写的频率会较高
        for (Book *b in p.books) {
            NSLog(@"%@ %@ %@", b.name, b.price, b.author);
        }
    }
    
//    for (Book *b in array) {
//        NSLog(@"%@ %@ %@", b.name, b.price, b.author);
//    }
}


修改数据

/**
 *  在常规开发中,应该首先加载所有的数据,帮顶到UITableView中,该数组中保存所有的Person记录,
 *  如果是这种情况,在修改个人记录时,是无需再次去查询数据库的。
 *
 *  在实际开发中,通常是从表格中选中某一行,获取到对应的NSManagedObject,然后进行修改
 *  如此,便可以只修改唯一一条记录了。
 */
- (void)updatePerson
{
    // 1. 实例化查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Book"];
    
    // 2. 设置谓词条件
    request.predicate = [NSPredicate predicateWithFormat:@"author CONTAINS '大忽悠'"];
    
    // 3. 由上下文查询数据
    NSArray *result = [_context executeFetchRequest:request error:nil];
    
    // 4. 输出结果
    for (Book *book in result) {
        NSLog(@"%@ %@ %@", book.name, book.author, book.price);
        
        // 更新书名
        book.name = @"西游记";
    }
    
    // 通知上下文保存保存
    [_context save:nil];
}



删除数据

- (void)removePerson
{
    // 1. 实例化查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
    
    // 2. 设置谓词条件
    request.predicate = [NSPredicate predicateWithFormat:@"name = '张老头'"];
    
    // 3. 由上下文查询数据
    NSArray *result = [_context executeFetchRequest:request error:nil];
    
    // 4. 输出结果
    for (Person *person in result) {
        NSLog(@"%@ %@ %@", person.name, person.age, person.phoneNo);
        
        // 删除一条记录
        [_context deleteObject:person];
        break;
    }
    
    // 5. 通知_context保存数据
    if ([_context save:nil]) {
        NSLog(@"删除成功");
    } else {
        NSLog(@"删除失败");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
旅游社交小程序功能有管理员和用户。管理员有个人中心,用户管理,每日签到管理,景点推荐管理,景点分类管理,防疫查询管理,美食推荐管理,酒店推荐管理,周边推荐管理,分享圈管理,我的收藏管理,系统管理。用户可以在微信小程序上注册登录,进行每日签到,防疫查询,可以在分享圈里面进行分享自己想要分享的内容,查看和收藏景点以及美食的推荐等操作。因而具有一定的实用性。 本站后台采用Java的SSM框架进行后台管理开发,可以在浏览器上登录进行后台数据方面的管理,MySQL作为本地数据库,微信小程序用到了微信开发者工具,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得旅游社交小程序管理工作系统化、规范化。 管理员可以管理用户信息,可以对用户信息添加修改删除。管理员可以对景点推荐信息进行添加修改删除操作。管理员可以对分享圈信息进行添加,修改,删除操作。管理员可以对美食推荐信息进行添加,修改,删除操作。管理员可以对酒店推荐信息进行添加,修改,删除操作。管理员可以对周边推荐信息进行添加,修改,删除操作。 小程序用户是需要注册才可以进行登录的,登录后在首页可以查看相关信息,并且下面导航可以点击到其他功能模块。在小程序里点击我的,会出现关于我的界面,在这里可以修改个人信息,以及可以点击其他功能模块。用户想要把一些信息分享到分享圈的时候,可以点击新增,然后输入自己想要分享的信息就可以进行分享圈的操作。用户可以在景点推荐里面进行收藏和评论等操作。用户可以在美食推荐模块搜索和查看美食推荐的相关信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值