zoukankan      html  css  js  c++  java
  • 数据库结构Sqlite与CoreData

    改章节是一篇关于数据库结构的帖子

        这两个就不是同一个层面的东西,core data是ORM框架+objects graph,它可以选择sqlite,xml,plist或是其他方式作为持久化方案。所以如果你仅仅须要一个持久化方案,你可以选择sqlite或是直接plist,如果你须要其他功能比如redo,undo,数据验证,或是方便的icloud等等额定的功能,就选择core data。

        iphone中 CoreData 框架的简略解释

        

        

    并非严厉的说,  CoreData是对sqlite数据库的一个封装.

    sqlite数据库操作的基本流程是, 创立数据库, 再通过定义一些字段来定义表格结构, 可以利用sql语句向表格中插入记载, 删除记载, 修改记载, 表格之间也可以建立联系.

    这个过程出现了, 表格的结构(schema), 全部表格的结构和互相联系构成整个数据库的模型, 数据库存放的方式(可以是文件或者在内存), 数据库操作, sql语句(主要是查询), 表格里头的记载

    上面将上面说的文字, 跟 CoreData的类作个对应:

    表格结构    --> NSEntityDescription
    数据库中全部表格和他们的联系 -->NSManagedObjectModel
    数据库存放方式 --> NSPersistentStoreCoordinator
    数据库操作 --> NSManagedObjectContext
    查询语句 --> NSFetchRequest
    表格的记载 --> NSManagedObject

    可能上面的对应关系并非非常严厉, 但确实可以帮助懂得.

    上面再看看 CoreData的类
    NSEntityDescription
    NSManagedObjectModel

    NSEntityDescription用来定义表格结构, 所以你就能够懂得NSManagedObjectModel中的setEntities:(NSArray *)entities函数大概有什么用了 . 通常, 定义model, 是用文件 CoreData.xcdatamodel, 可以图形化的操作. 这类似用nib来创立界面. 

    建个工程, 使用 coredata, 模拟器运行以后, 程序对应的document目录出现一个 CoreData.sqlite. 可以利用sqlite3命令来查看里头的表格结构
    用命令行sqlite3  CoreData.sqlite 进入
    >.tables
    ZEVENT        Z_METADATA    Z_PRIMARYKEY
    可以看到有表格ZEVENT, 对应的 CoreData.xcdatamodel文件有名字叫Event的Entity

    >.schema ZEVENT
    CREATE TABLE ZEVENT ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZTIMESTAMP TIMESTAMP );
    对应的Event中有属性timeStamp, 可以看到, 响应的ZEVENT表格中有字段TIMESTAMP

    > select * from ZEVENT
    1|1|1|306295807.974966
    2|1|1|306295810.981875
    3|1|1|306295811.982537
    这表格有三个记载, 可以用来初始化三个NSManagedObject, 修改了NSManagedObject, save以后也修改了表格记载

    你可以在 CoreData.xcdatamodel添加新的entity, 以后用sqlit3命令来查看数据库的变化

    NSPersistentStoreCoordinator
    这个类的对象通常用NSManagedObjectModel的对象来初始化, 这个类抽象出不同的存放方式, 最经常用的是NSSQLiteStoreType. 

    NSManagedObjectContext
    这个类的对象又用NSPersistentStoreCoordinator的对象来初始化, 它里头有些方法来添加, 删除NSManagedObject

    NSFetchRequest
    通常用NSEntityDescription来结构查询, 也就指定查询那个表格, 另外可以指定排序.

    CoreData的计划中, 下一层有响应的属性指向上一层, 所以NSManagedObject有属性得到NSEntityDescription, NSEntityDescription有属性得到NSManagedObjectModel.

    至于类
    NSFetchedResultsController, 只是又封了一下, 和NSFetchRequest合起来使用, 方便取数据, 另外和NSManagedObjectContext关联, 当数据库发生变化的时候收到通知.

    这文章只初步梳理了一下 CoreData各种的关系, 各种的方法还须要逐一研究. 文章最开始说 CoreData是对sqlite数据库的一个封装, 不是严厉的,  CoreData不一定用sqlit来实现, 但他们之间确实有种对应关系.

        


        

     

        

     

        

     

        

    使用SQLite3存储和读取数据

        

    SQLite3是嵌入在iOS中的关系型数据库,对于存储大规模的数据很有效。SQLite3使得不必将每个对象都加到内存中。

        

     
        每日一道理
    生命,是一场漫长的棋局。这盘棋没有猎猎西风,没有四起狼烟,只有在取舍和进退中抉择。只有像棋中的小卒那样,勇往直前,毫不退缩沿着沟沟坎坎的人生之路,艰难而执着的求索,前进,才会谱写人生最壮丽的强者之歌。

    SQLite3是嵌入在iOS中的关系型数据库,对于存储大规模的数据很有效。SQLite3使得不必将每个对象都加到内存中。

    基本操作:

    (1)打开或者创立数据库

    sqlite3 *database;
    int result = sqlite3_open("/path/databaseFile", &database);

    如果/path/databaseFile不存在,则创立它,否则打开它。如果result的值是SQLITE_OK,则标明我们的操作成功。

    注意上述语句中数据库文件的地址字符串前面没有@字符,它是一个C字符串。将NSString字符串转成C字符串的方法是:

    const char *cString = [nsString UTF8String];

     
    (2)关闭数据库

    sqlite3_close(database);


    (3)创立一个表格

    char *errorMsg;
    const char *createSQL = "CREATE TABLE IF NOT EXISTS PEOPLE (ID INTEGER PRIMARY KEY AUTOINCREMENT, FIELD_DATA TEXT)";
    int result = sqlite3_exec(database, createSQL, NULL, NULL, &errorMsg);

    执行以后,如果result的值是SQLITE_OK,则标明执行成功;否则,错误信息存储在errorMsg中。

    sqlite3_exec这个方法可以执行那些没有返回结果的操作,例如创立、插入、删除等。


    (4)查询操作

    NSString *query = @"SELECT ID, FIELD_DATA FROM FIELDS ORDER BY ROW";
    sqlite3_stmt *statement;
    int result = sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil);

    如果result的值是SQLITE_OK,则标明准备好statement,接下来执行查询: 

    while (sqlite3_step(statement) == SQLITE_ROW) {
        int rowNum = sqlite3_column_int(statement, 0);
        char *rowData = (char *)sqlite3_column_text(statement, 1);
        NSString *fieldValue = [[NSString alloc] initWithUTF8String:rowData];
        // Do something with the data here
    }
    sqlite3_finalize(statement);

    使用过其他数据库的话应该很好懂得这段语句,这个就是依次将每行的数据存在statement中,然后根据每行的字段取出数据。


    (5)使用约束变量

    实际操作时经常使用叫做约束变量的东西来结构SQL字符串,从而进行插入、查询或者删除等。

    例如,要执行带两个约束变量的插入操作,第一个变量是int类型,第二个是C字符串:

    char *sql = "insert into oneTable values (?, ?);";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(database, sql, -1, &stmt, nil) == SQLITE_OK) {
        sqlite3_bind_int(stmt, 1, 235);
        sqlite3_bind_text(stmt, 2, "valueString", -1, NULL);
    }
    if (sqlite3_step(stmt) != SQLITE_DONE)
        NSLog(@"Something is Wrong!");
    sqlite3_finalize(stmt);

    这里,sqlite3_bind_int(stmt, 1, 235);有三个参数:

    第一个是sqlite3_stmt类型的变量,在之前的sqlite3_prepare_v2中使用的。

    第二个是所约束变量的标签index。

    第三个参数是要加的值。

    有一些函数多出两个变量,例如

    sqlite3_bind_text(stmt, 2, "valueString", -1, NULL);

    这句,第四个参数代表第三个参数中须要传递的长度。对于C字符串来说,-1表示传递全部字符串。

    第五个参数是一个回调函数,比如执行后做内存清除工作。

    接下来,做个小例子吧!

    1、运行Xcode 4.3,新建一个Single View Application,名称为SQLite3 Test:

    数据库和结构


    2、连接SQLite3库:

    按照下图中的红色数字的顺序找到加号:

    数据库和结构


    单击这个加号,打开窗口,在搜索栏输入sqlite3:

    数据库和结构


    选择libsqlite3.dylib,单击Add,添加到工程。

    3、进行界面计划。打开ViewController.xib,使用Interface Builder计划界面如下:

    数据库和结构


    设置四个文本框的tag分别是1、2、3、4。

    4、在ViewController.h中添加属性和方法:

    @property (copy, nonatomic) NSString *databaseFilePath;
    
    - (void)applicationWillResignActive:(NSNotification *)notification;

    5、打开ViewController.m,向其中添加代码:

    5.1 在开头添加代码:

    #import "sqlite3.h"
    #define kDatabaseName @"database.sqlite3"

    5.2 在@implementation以后添加代码:

    @synthesize databaseFilePath;

    5.3 在viewDidLoad方法中添加代码:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        //获取数据库文件路径
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        self.databaseFilePath = [documentsDirectory stringByAppendingPathComponent:kDatabaseName];
        //打开或创立数据库
        sqlite3 *database;
        if (sqlite3_open([self.databaseFilePath UTF8String] , &database) != SQLITE_OK) {
            sqlite3_close(database);
            NSAssert(0, @"打开数据库失败!");
        }
        //创立数据库表
        NSString *createSQL = @"CREATE TABLE IF NOT EXISTS FIELDS (TAG INTEGER PRIMARY KEY, FIELD_DATA TEXT);";
        char *errorMsg;
        if (sqlite3_exec(database, [createSQL UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) {
            sqlite3_close(database);
            NSAssert(0, @"创立数据库表错误: %s", errorMsg);
        }
        //执行查询
        NSString *query = @"SELECT TAG, FIELD_DATA FROM FIELDS ORDER BY TAG";
        sqlite3_stmt *statement;
        if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
            //依次读取数据库表格FIELDS中每行的内容,并显示在对应的TextField
            while (sqlite3_step(statement) == SQLITE_ROW) {
                //获得数据
                int tag = sqlite3_column_int(statement, 0);
                char *rowData = (char *)sqlite3_column_text(statement, 1);
                //根据tag获得TextField
                UITextField *textField = (UITextField *)[self.view viewWithTag:tag];
                //设置文本
                textField.text = [[NSString alloc] initWithUTF8String:rowData];
            }
            sqlite3_finalize(statement);
        }
        //关闭数据库
        sqlite3_close(database);
        //当程序进入后台时执行写入数据库操作
        UIApplication *app = [UIApplication sharedApplication];
        [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(applicationWillResignActive:)
         name:UIApplicationWillResignActiveNotification
         object:app];
    }

    5.4 在@end之前实现方法:

    //程序进入后台时的操作,实现将当前显示的数据写入数据库
    - (void)applicationWillResignActive:(NSNotification *)notification {
        //打开数据库
        sqlite3 *database;
        if (sqlite3_open([self.databaseFilePath UTF8String], &database)
            != SQLITE_OK) {
            sqlite3_close(database);
            NSAssert(0, @"打开数据库失败!");
        }
        //向表格插入四行数据
        for (int i = 1; i <= 4; i++) { 
            //根据tag获得TextField
            UITextField *textField = (UITextField *)[self.view viewWithTag:i];
            //使用约束变量插入数据
            char *update = "INSERT OR REPLACE INTO FIELDS (TAG, FIELD_DATA) VALUES (?, ?);";
            sqlite3_stmt *stmt;
            if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) == SQLITE_OK) {
                sqlite3_bind_int(stmt, 1, i);
                sqlite3_bind_text(stmt, 2, [textField.text UTF8String], -1, NULL);
            }
            char *errorMsg = NULL;
            if (sqlite3_step(stmt) != SQLITE_DONE)
                NSAssert(0, @"更新数据库表FIELDS出错: %s", errorMsg);
            sqlite3_finalize(stmt);
        }
        //关闭数据库
        sqlite3_close(database);
    }

    6、实现关闭键盘,参考《iOS开发4:关闭键盘》中的第2步。其中,backgroundTap方法如下:

    //关闭键盘
    - (IBAction)backgroundTap:(id)sender {
        for (int i = 1; i <= 4; i++) {
            UITextField *textField = (UITextField *)[self.view viewWithTag:i];
            [textField resignFirstResponder];
        }
    }

    7、运行程序:

    刚运行时显示如上面左图:

    数据库和结构

    在各个文本框输入内容,如上面右图。然后按Home键,这样,就执行了写入数据的操作。

    第一次运行程序时,在SandBox的Documents目录下出现数据库文件database.sqlite3:

    数据库和结构


    此时退出程序,再次运行,则显示的就是上次退出时的值。

     

    转自:http://my.oschina.net/plumsoft/blog/57626

    文章结束给大家分享下程序员的一些笑话语录: PC软件体积大,是因为一个PC软件功能往往较多,能够满足你一个方面的需求,而一个iphone软件往往没几行代码,干一件很小的事情,自然需要的软件就多。就像吃西瓜和吃瓜子的来比数目,单位不同啊。

  • 相关阅读:
    python 杂谈
    python: list转字符串
    dataframe
    time模块
    python 调试器
    BAT机器学习面试1000题系列(41-45题)
    join()函数
    value_counts()
    模型评估
    04flask_scripts使用
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3080552.html
Copyright © 2011-2022 走看看