iOS數據存取(2)

SQLite3sql

SQLite3簡介數據庫

SQLite3是一款開源的嵌入式關係型數據庫,可移植性好、易使用、內存開銷小。框架

SQLite3是無類型的,意味着你能夠保存任何類型的數據到任意表的任意字段中。好比下列的創表語句是合法的:函數

1
create table t_person(name, age);

爲了保證可讀性,建議仍是把字段類型加上:url

1
create table t_person(name text, age integer);

SQLite3經常使用的5種數據類型:text、integer、float、boolean、blobspa

在iOS中使用SQLite3,首先要添加庫文件libsqlite3.dylib和導入主頭文件3d

1353118-d7cd70cf7fca9851.jpg

導入庫日誌

建立或打開數據庫code

1
2
3
// path爲:~/Documents/person.db
sqlite3 *db;
int result = sqlite3_open([path UTF8String], &db);

代碼解析:orm

  • sqlite3_open()將根據文件路徑打開數據庫,若是不存在,則會建立一個新的數據庫。若是result等於常量SQLITE_OK,則表示成功打開數據庫

  • sqlite3 *db:一個打開的數據庫實例

  • 數據庫文件的路徑必須以C字符串(而非NSString)傳入

關閉數據庫:sqlite3_close(db);

執行創表語句

1
2
3
char *errorMsg;   // 用來存儲錯誤信息
char *sql =  "create table if not exists t_person(id integer primary key autoincrement, name text, age integer);" ;
int result = sqlite3_exec(db, sql, NULL, NULL, &errorMsg);

代碼解析:

  • sqlite3_exec()能夠執行任何SQL語句,好比創表、更新、插入和刪除操做。可是通常不用它執行查詢語句,由於它不會返回查詢到的數據

  • sqlite3_exec()還能夠執行的語句:

  • 開啓事務:begin transaction;

  • 回滾事務:rollback;

  • 提交事務:commit;

帶佔位符插入數據

1
2
3
4
5
6
7
8
9
10
char *sql =  "insert into t_person(name, age) values(?, ?);" ;
sqlite3_stmt *stmt;
if  (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
     sqlite3_bind_text(stmt, 1,  "母雞" , -1, NULL);
     sqlite3_bind_int(stmt, 2, 27);
}
if  (sqlite3_step(stmt) != SQLITE_DONE) {
     NSLog(@ "插入數據錯誤" );
}
sqlite3_finalize(stmt);

代碼解析:

  • sqlite3_prepare_v2()返回值等於SQLITE_OK,說明SQL語句已經準備成功,沒有語法問題

  • sqlite3_bind_text():大部分綁定函數都只有3個參數

  • 第1個參數是sqlite3_stmt *類型

  • 第2個參數指佔位符的位置,第一個佔位符的位置是1,不是0

  • 第3個參數指佔位符要綁定的值

  • 第4個參數指在第3個參數中所傳遞數據的長度,對於C字符串,能夠傳遞-1代替字符串的長度

  • 第5個參數是一個可選的函數回調,通常用於在語句執行後完成內存清理工做

  • sqlite_step():執行SQL語句,返回SQLITE_DONE表明成功執行完畢

  • sqlite_finalize():銷燬sqlite3_stmt *對象

查詢數據

1
2
3
4
5
6
7
8
9
10
11
12
char *sql =  "select id,name,age from t_person;" ;
sqlite3_stmt *stmt;
if  (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
     while  (sqlite3_step(stmt) == SQLITE_ROW) {
         int _id = sqlite3_column_int(stmt, 0);
         char *_name = (char *)sqlite3_column_text(stmt, 1);
         NSString *name = [NSString stringWithUTF8String:_name];
         int _age = sqlite3_column_int(stmt, 2);
         NSLog(@ "id=%i, name=%@, age=%i" , _id, name, _age);
     }
}
sqlite3_finalize(stmt);

代碼解析

  • sqlite3_step()返回SQLITE_ROW表明遍歷到一條新記錄

  • sqlite3_column_*()用於獲取每一個字段對應的值,第2個參數是字段的索引,從0開始

Core Data

Core Data簡單介紹

  • Core Data框架提供了對象-關係映射(ORM)的功能,即可以將OC對象轉化成數據,保存在SQLite3數據庫文件中,也可以將保存在數據庫中的數據還原成OC對象。在此數據操做期間,不須要編寫任何SQL語句。使用此功能,要添加CoreData.framework和導入主頭文件CoreData/CoreData.h。

1353118-801e5c3548ba5238.jpg

對象-關係映射

  • 在Core Data,須要進行映射的對象稱爲實體(entity),並且須要使用Core Data的模型文件來描述應用的全部實體和實體屬性

這裏以Person和Card(身份證)2個實體爲例子,先看看實體屬性和之間的關聯關係

1353118-bcb9d93c189ca107.jpg

實體屬性和之間的關聯關係

  • Person中有個Card屬性,Card中有個Person屬性。

  • 屬於一對一雙向關聯。

模型文件

建立文件

1353118-847db2b702ae2142.jpg

添加實體

1353118-8e522e29273d4c03.png

添加Person實體的基本屬性

1353118-3c28a1adca613a50.jpg

添加Card實體的基本屬性

1353118-e5bc2b8fa5ccce37.jpg

在Person中添加card屬性

1353118-816276353724915a.jpg

在Card中添加person屬性

1353118-8bb511e4742b94f7.jpg

NSManagedObject

  • 經過Core Data從數據庫取出的對象,默認狀況下都是NSManagedObject對象

  • NSManagedObject的工做模式有點相似於NSDictionary對象,經過鍵-值對來存取全部的實體屬性

  • setValue:forKey: 存儲屬性值(屬性名爲key)

  • valueForKey: 獲取屬性值(屬性名爲key)

1353118-21be3c3c51f728ac.jpg

Core Data主要對象

1353118-e79a0387a70eb1cb.jpg

搭建Core Data上下文環境

從應用程序包中加載模型文件

1
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];

傳入模型,初始化NSPersistentStoreCoordinator

1
NSPersistentStoreCoordinator *psc = [[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model] autorelease];

構建SQLite文件路徑

1
2
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *url = [NSURL fileURLWithPath:[docs stringByAppendingPathComponent:@ "person.data" ]];

添加持久化存儲庫,這裏使用SQLite做爲存儲庫

1
2
3
4
5
NSError *error = nil;
NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
if  (store == nil) {  // 直接拋異常
   [NSException raise:@ "添加數據庫錯誤"  format:@ "%@" , [error localizedDescription]];
}

初始化上下文,設置persistentStoreCoordinator屬性

1
2
3
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
context.persistentStoreCoordinator = psc;
// 用完以後,仍是要[context release];

添加數據

傳入上下文,建立一個Person實體對象

1
NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@ "Person"  inManagedObjectContext:context];

設置簡單屬性

1
2
[person setValue:@ "hosea"  forKey:@ "name" ];
[person setValue:[NSNumber numberWithInt:22] forKey:@ "age" ];

傳入上下文,建立一個Card實體對象

1
2
NSManagedObject *card = [NSEntityDescription insertNewObjectForEntityForName:@ "Card"  inManagedObjectContext:context];
[card setValue:@ "4414241933432"  forKey:@ "no" ];

設置Person和Card之間的關聯關係

1
[person setValue:card forKey:@ "card" ];

利用上下文對象,將數據同步到持久化存儲庫

1
2
3
4
5
6
NSError *error = nil;
BOOL success = [context save:&error];
if  (!success) {
   [NSException raise:@ "訪問數據庫錯誤"  format:@ "%@" , [error localizedDescription]];
}
//若是是想作更新操做:只要在更改了實體對象的屬性後調用[context save:&error],就能將更改的數據同步到數據庫

查詢數據

初始化一個查詢請求

1
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];

設置要查詢的實體

1
NSEntityDescription *desc = [NSEntityDescription entityForName:@ "Person"  inManagedObjectContext:context];

設置排序(按照age降序)

1
2
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@ "age"  ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:sort];

設置條件過濾(name like '%hosea-1%')

1
2
NSPredicate *predicate = [NSPredicate predicateWithFormat:@ "name like %@" , @ "*hosea-1*" ];
request.predicate = predicate;

執行請求

1
2
3
4
5
NSError *error = nil;
NSArray *objs = [context executeFetchRequest:request error:&error];
if  (error) {
   [NSException raise:@ "查詢錯誤"  format:@ "%@" , [error localizedDescription]];
}

遍歷數據

1
2
3
for  (NSManagedObject *obj  in  objs) {
   NSLog(@ "name=%@" , [obj valueForKey:@ "name" ]);
}

刪除數據

傳入須要刪除的實體對象

1
[context deleteObject:managedObject];

將結果同步到數據庫

1
2
3
4
5
NSError *error = nil;
[context save:&error];
if  (error) {
   [NSException raise:@ "刪除錯誤"  format:@ "%@" , [error localizedDescription]];
}

打開Core Data的SQL日誌輸出開關

1353118-5d4b45107f5a7280.jpg

Core Data的延遲加載

  • Core Data不會根據實體中的關聯關係當即獲取相應的關聯對象

  • 好比經過Core Data取出Person實體時,並不會當即查詢相關聯的Card實體;當應用真的須要使用Card時,纔會查詢數據庫,加載Card實體的信息

建立NSManagedObject的子類

默認狀況下,利用Core Data取出的實體都是NSManagedObject類型的,可以利用鍵-值對來存取數據

可是通常狀況下,實體在存取數據的基礎上,有時還須要添加一些業務方法來完成一些其餘任務,那麼就必須建立NSManagedObject的子類

1353118-0ae824488f87d4c7.jpg

選擇模型文件

1353118-ad48dc961b0dc63b.jpg

選擇須要建立子類的實體

1353118-7d62d41d5e888d25.jpg

1353118-c2e164c1d17cd6ee.jpg

那麼生成一個Person實體對象就應該這樣寫

1
2
3
4
5
6
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@ "Person"  inManagedObjectContext:context];
person.name = @ "hosea" ;
person.age = [NSNumber numberWithInt:22];
Card *card = [NSEntityDescription insertNewObjectForEntityForName:@」Card" inManagedObjectContext:context];
card.no = @」4414245465656";
person.card = card;
相關文章
相關標籤/搜索