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(@"删除失败");
    }
}

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值