国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

從C#到Objective-C,循序漸進(jìn)學(xué)習(xí)蘋果開發(fā)(7)--使用FMDB對(duì)Sqlite數(shù)據(jù)庫(kù)進(jìn)行操作

2019-11-14 20:33:39
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

本隨筆系列主要介紹從一個(gè)Windows平臺(tái)從事C#開發(fā)到Mac平臺(tái)蘋果開發(fā)的一系列感想和體驗(yàn)歷程,本系列文章是在起步階段逐步積累的,希望帶給大家更好,更真實(shí)的轉(zhuǎn)換歷程體驗(yàn)。本篇主要開始介紹基于XCode進(jìn)行IOS程序的開發(fā),介紹使用FMDB對(duì)Sqlite數(shù)據(jù)庫(kù)進(jìn)行操作,以及對(duì)數(shù)據(jù)庫(kù)操作類進(jìn)行抽象設(shè)計(jì),以期達(dá)到重用、簡(jiǎn)化、高效開發(fā)的目的。

在.NET領(lǐng)域開發(fā)了很多年,一般常見(jiàn)的項(xiàng)目都需要操作數(shù)據(jù)庫(kù),包括有Oracle、SqlServer、MySQL、Sqlite、access等數(shù)據(jù)庫(kù),這些數(shù)據(jù)庫(kù)是很常見(jiàn)的,我們?cè)?NET環(huán)境里面開發(fā)的各種系統(tǒng),可能都或多或少需要和其中一種以上的數(shù)據(jù)庫(kù)打交道,這也是我致力于提煉我的.NET領(lǐng)域的Winform開發(fā)框架、Web開發(fā)框架、混合式開發(fā)框架的目的,盡可能達(dá)到簡(jiǎn)化、重用、高效開發(fā)的目的。

雖然現(xiàn)在在IOS領(lǐng)域做一些研究開發(fā),即使IOS設(shè)備更多強(qiáng)調(diào)的是一個(gè)多媒體的設(shè)備,但是數(shù)據(jù)庫(kù)的操作還是必不可少,因此我先從我熟悉的數(shù)據(jù)庫(kù)這塊入手,了解其中數(shù)據(jù)庫(kù)是如何操作的,有哪些現(xiàn)成的組件進(jìn)行參考學(xué)習(xí)等等。

在IOS里面開發(fā),提起和數(shù)據(jù)庫(kù)打交道,可能很多人都熟悉FMDB這個(gè)數(shù)據(jù)庫(kù)的組件,它對(duì)IOS里面操作Sqlite數(shù)據(jù)庫(kù)進(jìn)行了很大程度的簡(jiǎn)化,簡(jiǎn)化后,我們大多數(shù)情況下,只需要和FMDatabase和FMResultSet打交道即可,使用起來(lái)非常方便。

1、FMDB的操作

為了較好介紹整體性的內(nèi)容,我們先從FMDB的各種操作進(jìn)行介紹。

1)數(shù)據(jù)庫(kù)打開操作

FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;  if (![db open]) {  NSLog(@"無(wú)法打開數(shù)據(jù)庫(kù)");  return ;  }  

2)數(shù)據(jù)庫(kù)操作executeUpdate

使用FMDB,對(duì)于沒(méi)有返回記錄的操作,都可以用executeUpdate進(jìn)行操作,如下是刪除記錄的函數(shù)

- (BOOL) deleteByCondition:(NSString *) condition {    NSString *query = [NSString stringWithFormat:@"Delete FROM %@ Where %@ ", self.tableName, condition];    BOOL result = [self.database executeUpdate:query];    return result;}

當(dāng)然,對(duì)于SQLite很多數(shù)據(jù)庫(kù)操作,我們可以使用參數(shù)化語(yǔ)句進(jìn)行操作,如下例子所示

[db executeUpdate:@"INSERT INTO User (Name,Age) VALUES (?,?)",@"張三",[NSNumber numberWithInt:30]]  

參數(shù)化也可以使用 : 字符作為參數(shù)標(biāo)識(shí),如下所示,是我封裝的一個(gè)數(shù)據(jù)庫(kù)操作函數(shù)

- (BOOL) deleteById:(id) key{    NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:key, @"id", nil];    NSString *query = [NSString stringWithFormat:@"Delete FROM %@ Where %@ =:id", self.tableName, self.PRimaryKey];    BOOL result = [self.database executeUpdate:query withParameterDictionary:argsDict];    return result;}

3)返回集合的操作

操作有返回集合的語(yǔ)句,我們就需要用到FMResultSet對(duì)象了,這個(gè)對(duì)象類似于以前見(jiàn)過(guò)的游標(biāo),不過(guò)不一樣的東西而已。

FMResultSet *rs=[db executeQuery:@"SELECT * FROM User"];rs=[db executeQuery:@"SELECT * FROM User WHERE Age = ?",@"20"];while ([rs next]){NSLog(@"%@ %@",[rs stringForColumn:@"Name"],[rs stringForColumn:@"Age"]);}

上面的代碼操作,返回一個(gè)Resultset集合進(jìn)行遍歷使用,我們可以根據(jù)Resultset的一些方法獲取到不同的數(shù)據(jù)內(nèi)容。

相對(duì)于FMResult的操作方式,原生態(tài)的Sqlite數(shù)據(jù)庫(kù)操作代碼如下所示。看完是不是感覺(jué)使用FMDB類庫(kù)操作數(shù)據(jù)庫(kù)方便很多呢。

 NSString *sqlQuery = @"SELECT * FROM User";    sqlite3_stmt * statement;        if (sqlite3_prepare_v2(db, [sqlQuery UTF8String], -1, &statement, nil) == SQLITE_OK) {        while (sqlite3_step(statement) == SQLITE_ROW) {            char *name = (char*)sqlite3_column_text(statement, 1);            NSString *nsNameStr = [[NSString alloc]initWithUTF8String:name];            int age = sqlite3_column_int(statement, 2);            char *address = (char*)sqlite3_column_text(statement, 3);            NSString *nsAddressStr = [[NSString alloc]initWithUTF8String:address];                        NSLog(@"name:%@  age:%d  address:%@",nsNameStr,age, nsAddressStr);        }    }    sqlite3_close(db);

FMResultSet方法有下面幾種,分別用于獲取不同的數(shù)據(jù):

  • intForColumn:
  • longForColumn:
  • longLongIntForColumn:
  • boolForColumn:
  • doubleForColumn:
  • stringForColumn:
  • dateForColumn:
  • dataForColumn:
  • dataNoCopyForColumn:
  • UTF8StringForColumnIndex:
  • objectForColumn:

2、數(shù)據(jù)庫(kù)操作層的設(shè)計(jì)

上面小節(jié)介紹了使用FMDB類庫(kù)對(duì)Sqlite數(shù)據(jù)庫(kù)的操作,使我們大致了解了在IOS里面對(duì)數(shù)據(jù)庫(kù)操作的過(guò)程。但是單純?nèi)绻榻B這些,我覺(jué)得太泛泛了,而且對(duì)我們使用起來(lái)也還是很不方便,很多時(shí)候,我總是想通過(guò)設(shè)計(jì)的方式,來(lái)簡(jiǎn)化我的各種操作處理。如我們知道,IOS里面的Objective C也提供了很多高級(jí)語(yǔ)言都有的屬性,如對(duì)象繼承,接口、多態(tài)等等。

我很早之前寫過(guò)的隨筆《Winform開發(fā)框架之?dāng)?shù)據(jù)訪問(wèn)層的設(shè)計(jì)》 ,介紹了我在.NET領(lǐng)域里面的數(shù)據(jù)庫(kù)訪問(wèn)層的設(shè)計(jì),由于這種設(shè)計(jì),能很大程度上減少代碼量,并提高開發(fā)效率,因此,我也想再IOS里面形成這樣的數(shù)據(jù)訪問(wèn)設(shè)計(jì),雖然IOS里面可能主要是使用單機(jī)版的數(shù)據(jù)庫(kù),如SQLite數(shù)據(jù)庫(kù),所以我想簡(jiǎn)化一些.NET里面的設(shè)計(jì)模型。

在.NET里面,我的框架分層主要如下所示,這種框架的設(shè)計(jì)模式,已經(jīng)很好應(yīng)用在了我的Winform開發(fā)框架、WCF及混合式開發(fā)框架、Web框架里面。它們常見(jiàn)的分層模式,可以分為UI層、BLL層、DAL層、IDAL層、Entity層、公用類庫(kù)層等等

 而其中的DAL層的設(shè)計(jì),示意圖如下所示,DAL層主要是通過(guò)繼承自BaseDAL基類(如BaseDALSQL)進(jìn)行, BaseDALSQL進(jìn)行更高一層的抽象,已達(dá)到更好的應(yīng)用目的。

 

而我們?cè)贗OS里面,則可以主要考慮SQLite數(shù)據(jù)庫(kù)即可,因此,我把設(shè)計(jì)通過(guò)簡(jiǎn)化,構(gòu)造下面的設(shè)計(jì)模型

 

在項(xiàng)目里面,數(shù)據(jù)訪問(wèn)層的文件如下所示(為了演示測(cè)試方便,使用User表進(jìn)行操作)。

為了實(shí)現(xiàn)數(shù)據(jù)的承載,我們需要把表的數(shù)據(jù)轉(zhuǎn)換為實(shí)體類進(jìn)行顯示和操作,因此實(shí)體類的設(shè)計(jì)也需要考慮好。由于數(shù)據(jù)訪問(wèn)層的基類,封裝了大多數(shù)的數(shù)據(jù)操作,也包括返回的數(shù)據(jù)對(duì)象和集合,因此數(shù)據(jù)訪問(wèn)層的基類,也涉及到了數(shù)據(jù)類型返回的問(wèn)題。

由于IOS里面的Objective C里面沒(méi)有泛型這樣的東西,因此有兩種方式可以來(lái)實(shí)現(xiàn)基類實(shí)體類的處理:一是使用動(dòng)態(tài)類型id類型作為實(shí)體類類型,一種是使用一種半類型化的類型(實(shí)體類的基類)作為對(duì)象,我傾向于使用后者,因?yàn)楫吘贡容^接近真實(shí)的類型了。

////  BaseEntity.h//  MyDatabaseProject////  Created by 伍華聰 on 14-4-2.//  Copyright (c) 2014年 伍華聰. All rights reserved.//#import <Foundation/Foundation.h>@interface BaseEntity : NSObject@end
////  UserInfo.h//  MyDatabaseProject////  Created by 伍華聰 on 14-3-30.//  Copyright (c) 2014年 伍華聰. All rights reserved.//#import <Foundation/Foundation.h>#import "BaseEntity.h"@interface UserInfo : BaseEntity@property(nonatomic, copy) NSString *ID;@property(nonatomic, copy) NSString *name;@property(nonatomic, copy) NSString *fullName;@end

這種繼承模式和.NET的繼承關(guān)系差不多了。

對(duì)于數(shù)據(jù)訪問(wèn)層的設(shè)計(jì)代碼,它就是在數(shù)據(jù)訪問(wèn)基類的定義如下,基類使用了FMDB的數(shù)據(jù)訪問(wèn)類進(jìn)行操作的,里面很多操作的接口就是模仿我在.NET領(lǐng)域里面的數(shù)據(jù)訪問(wèn)層的設(shè)計(jì)。

////  BaseDAL.h//  MyDatabaseProject////  Created by 伍華聰 on 14-3-30.//  Copyright (c) 2014年 伍華聰. All rights reserved.//#import <Foundation/Foundation.h>#import "FMDatabase.h"#import "BaseEntity.h"@interface BaseDAL : NSObject{    NSString *pathToDatabase;}#pragma 數(shù)據(jù)庫(kù)相關(guān)屬性@property (nonatomic, strong) NSString *pathToDatabase;@property (nonatomic, readonly) FMDatabase *database;  // 數(shù)據(jù)庫(kù)操作對(duì)象@property (nonatomic, strong) NSString *tableName;//表名稱@property (nonatomic, strong) NSString *primaryKey;//主鍵@property (nonatomic, strong) NSString *sortField;//排序,默認(rèn)為主鍵@property (nonatomic, assign, getter=isDescending) BOOL descending;//是否降序查詢//將DataReader的屬性值轉(zhuǎn)化為實(shí)體類的屬性值,返回實(shí)體類(子類必須重寫)-(id) rsToEntity:(FMResultSet *)rs;//將實(shí)體對(duì)象的屬性值轉(zhuǎn)化為字典列表對(duì)應(yīng)的鍵值(子類必須重寫)-(NSDictionary *) dictByEntity:(BaseEntity *) info;#pragma 基礎(chǔ)操作接口//根據(jù)指定對(duì)象的ID,從數(shù)據(jù)庫(kù)中刪除指定對(duì)象- (BOOL) deleteById:(id) key;//根據(jù)指定條件,從數(shù)據(jù)庫(kù)中刪除指定對(duì)象- (BOOL) deleteByCondition:(NSString *) condition;//更新對(duì)象屬性到數(shù)據(jù)庫(kù)中-(BOOL) update:(BaseEntity *) info byKey:(id) key;//插入指定對(duì)象到數(shù)據(jù)庫(kù)中-(BOOL) insert:(BaseEntity *) info;//插入指定對(duì)象到數(shù)據(jù)庫(kù)中,并返回最后插入的ID-(NSInteger) insert2:(BaseEntity *) info;//查詢數(shù)據(jù)庫(kù),檢查是否存在指定ID的對(duì)象- (BaseEntity *) findById:(id) key;//根據(jù)條件查詢數(shù)據(jù)庫(kù),如果存在返回第一個(gè)對(duì)象-(BaseEntity *) findSingle:(NSString *) condition;//根據(jù)條件查詢數(shù)據(jù)庫(kù),如果存在返回第一個(gè)對(duì)象-(BaseEntity *) findSingle:(NSString *) condition orderBy:(NSString *) orderBy;//根據(jù)條件查詢數(shù)據(jù)庫(kù),并返回對(duì)象集合- (NSArray *) find:(NSString *) condition;//根據(jù)條件查詢數(shù)據(jù)庫(kù),并返回對(duì)象集合- (NSArray *) find:(NSString *) condition orderBy:(NSString *) orderBy;//獲取表的全部數(shù)據(jù)- (NSArray *) getAll;//獲取表的全部數(shù)據(jù)- (NSArray *) getAll:(NSString *) orderBy;//獲取某字段數(shù)據(jù)字典列表-(NSArray *) getFieldList:(NSString *) fieldName;//獲取表的所有記錄數(shù)量-(int) getRecordCount;//根據(jù)條件,獲取表查詢的記錄數(shù)量-(int) getRecordCount:(NSString *) condition;//根據(jù)條件,判斷是否存在記錄-(BOOL) isExistRecord:(NSString *)condition;//查詢數(shù)據(jù)庫(kù),檢查是否存在指定鍵值的對(duì)象-(BOOL) isExist:(NSString *)fieldName value:(id) value;//根據(jù)主鍵和字段名稱,獲取對(duì)應(yīng)字段的內(nèi)容-(NSString *) getFieldValue:(NSString *)key fieldName:(NSString *)fieldName;//執(zhí)行SQL查詢語(yǔ)句,返回查詢結(jié)果的所有記錄的第一個(gè)字段,用逗號(hào)分隔。-(NSString *) sqlValueList:(NSString *)query;#pragma 數(shù)據(jù)庫(kù)初始化函數(shù)及關(guān)閉操作//根據(jù)SQLite數(shù)據(jù)庫(kù)地址初始化數(shù)據(jù)庫(kù)-(id) initWithPath:(NSString *)filePath;//根據(jù)SQLite數(shù)據(jù)庫(kù)名稱初始化數(shù)據(jù)庫(kù)-(id) initWithFileName:(NSString *)fileName;// 關(guān)閉連接-(void) close;@end

和我的.NET框架里面的數(shù)據(jù)訪問(wèn)層設(shè)計(jì)一樣,數(shù)據(jù)訪問(wèn)基類已經(jīng)封裝了大多數(shù)的數(shù)據(jù)訪問(wèn)操作,因此各個(gè)表的數(shù)據(jù)訪問(wèn)對(duì)象,它的代碼就可以很簡(jiǎn)潔了。從上面的基類接口設(shè)計(jì)可以看到,里面一些實(shí)體類返回函數(shù)或者列表返回函數(shù),都使用了BaseEntity作為對(duì)象,我們具體在起子類使用的時(shí)候,把它返回的對(duì)象再一次轉(zhuǎn)換即可。對(duì)于數(shù)據(jù)庫(kù)訪問(wèn)基類,我們以一個(gè)返回集合的接口實(shí)現(xiàn)來(lái)分析。

- (NSArray *) find:(NSString *) condition orderBy:(NSString *) orderBy {    NSString *query = [NSString stringWithFormat:@"SELECT * FROM %@ ", self.tableName];    if (condition != nil) {        query = [query stringByAppendingFormat:@" where %@ ", condition];    }        if (orderBy != nil) {        query = [query stringByAppendingString:orderBy];    }    else {        query = [query stringByAppendingFormat:@" ORDER BY %@ %@ ", self.sortField, self.isDescending ? @"DESC" : @"ASC"];    }        FMResultSet *rs = [self.database executeQuery:query];    NSMutableArray *array = [NSMutableArray arrayWithCapacity:[rs columnCount]];        BaseEntity *info = nil; //默認(rèn)初始化為空    while ([rs next]) {        info = [self rsToEntity:rs];        [array addObject:info];    }    [rs close];        return array;}

上面代碼使用了參數(shù)化的SQL語(yǔ)句進(jìn)行查詢,并且,對(duì)返回的數(shù)據(jù)庫(kù)的ResultSet進(jìn)行轉(zhuǎn)換為實(shí)體類。

info = [self rsToEntity:rs];

由于基類封裝了大多數(shù)的數(shù)據(jù)庫(kù)操作函數(shù),因此數(shù)據(jù)訪問(wèn)層的具體表的實(shí)現(xiàn)類,可以很簡(jiǎn)潔,但是已經(jīng)具備了常見(jiàn)的CRUD操作,以及一些分頁(yè)查詢等復(fù)雜的數(shù)據(jù)操作功能。

////  UserDAL.h//  MyDatabaseProject////  Created by 伍華聰 on 14-3-30.//  Copyright (c) 2014年 伍華聰. All rights reserved.//#import <Foundation/Foundation.h>#import "FMDatabase.h"#import "BaseDAL.h"#import "UserInfo.h"@interface UserDAL : BaseDAL{}//單例模式+(UserDAL *) defaultDAL;@end

基于篇幅的原因,我將在下一篇介紹如何在界面層中使用這樣的數(shù)據(jù)訪問(wèn)設(shè)計(jì)類,先放上一些測(cè)試程序的界面截圖。

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 乌拉特前旗| 格尔木市| 金平| 宁远县| 南城县| 禹城市| 西昌市| 遂川县| 慈利县| 莒南县| 化德县| 团风县| 五指山市| 青铜峡市| 砚山县| 昌乐县| 台东市| 樟树市| 正定县| 建水县| 惠水县| 洛扎县| 太保市| 麦盖提县| 庄浪县| 孟州市| 都安| 汝阳县| 高州市| 会理县| 田东县| 武隆县| 盐亭县| 高尔夫| 平昌县| 资中县| 新和县| 手游| 商南县| 新闻| 漯河市|