程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 從C#到Objective-C,循序漸進學習蘋果開發(7)--使用FMDB對Sqlite數據庫進行操作

從C#到Objective-C,循序漸進學習蘋果開發(7)--使用FMDB對Sqlite數據庫進行操作

編輯:C#入門知識

本隨筆系列主要介紹從一個Windows平台從事C#開發到Mac平台蘋果開發的一系列感想和體驗歷程,本系列文章是在起步階段逐步積累的,希望帶給大家更好,更真實的轉換歷程體驗。本篇主要開始介紹基於XCode進行IOS程序的開發,介紹使用FMDB對Sqlite數據庫進行操作,以及對數據庫操作類進行抽象設計,以期達到重用、簡化、高效開發的目的。   在.NET領域開發了很多年,一般常見的項目都需要操作數據庫,包括有Oracle、SqlServer、Mysql、Sqlite、Access等數據庫,這些數據庫是很常見的,我們在.NET環境裡面開發的各種系統,可能都或多或少需要和其中一種以上的數據庫打交道,這也是我致力於提煉我的.NET領域的Winform開發框架、Web開發框架、混合式開發框架的目的,盡可能達到簡化、重用、高效開發的目的。   雖然現在在IOS領域做一些研究開發,即使IOS設備更多強調的是一個多媒體的設備,但是數據庫的操作還是必不可少,因此我先從我熟悉的數據庫這塊入手,了解其中數據庫是如何操作的,有哪些現成的組件進行參考學習等等。   在IOS裡面開發,提起和數據庫打交道,可能很多人都熟悉FMDB這個數據庫的組件,它對IOS裡面操作Sqlite數據庫進行了很大程度的簡化,簡化後,我們大多數情況下,只需要和FMDatabase和FMResultSet打交道即可,使用起來非常方便。   1、FMDB的操作   為了較好介紹整體性的內容,我們先從FMDB的各種操作進行介紹。   1)數據庫打開操作   FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;   if (![db open]) {   NSLog(@"無法打開數據庫");   return ;   }   2)數據庫操作executeUpdate   使用FMDB,對於沒有返回記錄的操作,都可以用executeUpdate進行操作,如下是刪除記錄的函數   - (BOOL) deleteByCondition:(NSString *) condition {     NSString *query = [NSString stringWithFormat:@"Delete FROM %@ Where %@ ", self.tableName, condition];     BOOL result = [self.database executeUpdate:query];     return result; } 當然,對於SQLite很多數據庫操作,我們可以使用參數化語句進行操作,如下例子所示   [db executeUpdate:@"INSERT INTO User (Name,Age) VALUES (?,?)",@"張三",[NSNumber numberWithInt:30]]   參數化也可以使用 : 字符作為參數標識,如下所示,是我封裝的一個數據庫操作函數   復制代碼 - (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)返回集合的操作   操作有返回集合的語句,我們就需要用到FMResultSet對象了,這個對象類似於以前見過的游標,不過不一樣的東西而已。   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"]); } 上面的代碼操作,返回一個Resultset集合進行遍歷使用,我們可以根據Resultset的一些方法獲取到不同的數據內容。   相對於FMResult的操作方式,原生態的Sqlite數據庫操作代碼如下所示。看完是不是感覺使用FMDB類庫操作數據庫方便很多呢。   復制代碼  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方法有下面幾種,分別用於獲取不同的數據:   intForColumn: longForColumn: longLongIntForColumn: boolForColumn: doubleForColumn: stringForColumn: dateForColumn: dataForColumn: dataNoCopyForColumn: UTF8StringForColumnIndex: objectForColumn: 2、數據庫操作層的設計   上面小節介紹了使用FMDB類庫對Sqlite數據庫的操作,使我們大致了解了在IOS裡面對數據庫操作的過程。但是單純如果介紹這些,我覺得太泛泛了,而且對我們使用起來也還是很不方便,很多時候,我總是想通過設計的方式,來簡化我的各種操作處理。如我們知道,IOS裡面的Objective C也提供了很多高級語言都有的屬性,如對象繼承,接口、多態等等。   我很早之前寫過的隨筆《Winform開發框架之數據訪問層的設計》 ,介紹了我在.NET領域裡面的數據庫訪問層的設計,由於這種設計,能很大程度上減少代碼量,並提高開發效率,因此,我也想再IOS裡面形成這樣的數據訪問設計,雖然IOS裡面可能主要是使用單機版的數據庫,如SQLite數據庫,所以我想簡化一些.NET裡面的設計模型。   在.NET裡面,我的框架分層主要如下所示,這種框架的設計模式,已經很好應用在了我的Winform開發框架、WCF及混合式開發框架、Web框架裡面。它們常見的分層模式,可以分為UI層、BLL層、DAL層、IDAL層、Entity層、公用類庫層等等        而其中的DAL層的設計,示意圖如下所示,DAL層主要是通過繼承自BaseDAL基類(如BaseDALSQL)進行, BaseDALSQL進行更高一層的抽象,已達到更好的應用目的。       而我們在IOS裡面,則可以主要考慮SQLite數據庫即可,因此,我把設計通過簡化,構造下面的設計模型       在項目裡面,數據訪問層的文件如下所示(為了演示測試方便,使用User表進行操作)。       為了實現數據的承載,我們需要把表的數據轉換為實體類進行顯示和操作,因此實體類的設計也需要考慮好。由於數據訪問層的基類,封裝了大多數的數據操作,也包括返回的數據對象和集合,因此數據訪問層的基類,也涉及到了數據類型返回的問題。   由於IOS裡面的Objective C裡面沒有泛型這樣的東西,因此有兩種方式可以來實現基類實體類的處理:一是使用動態類型id類型作為實體類類型,一種是使用一種半類型化的類型(實體類的基類)作為對象,我傾向於使用後者,因為畢竟比較接近真實的類型了。   復制代碼 // //  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的繼承關系差不多了。   對於數據訪問層的設計代碼,它就是在數據訪問基類的定義如下,基類使用了FMDB的數據訪問類進行操作的,裡面很多操作的接口就是模仿我在.NET領域裡面的數據訪問層的設計。   復制代碼 // //  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 數據庫相關屬性   @property (nonatomic, strong) NSString *pathToDatabase; @property (nonatomic, readonly) FMDatabase *database;  // 數據庫操作對象 @property (nonatomic, strong) NSString *tableName;//表名稱 @property (nonatomic, strong) NSString *primaryKey;//主鍵 @property (nonatomic, strong) NSString *sortField;//排序,默認為主鍵 @property (nonatomic, assign, getter=isDescending) BOOL descending;//是否降序查詢     //將DataReader的屬性值轉化為實體類的屬性值,返回實體類(子類必須重寫) -(id) rsToEntity:(FMResultSet *)rs;   //將實體對象的屬性值轉化為字典列表對應的鍵值(子類必須重寫) -(NSDictionary *) dictByEntity:(BaseEntity *) info;     #pragma 基礎操作接口   //根據指定對象的ID,從數據庫中刪除指定對象 - (BOOL) deleteById:(id) key;   //根據指定條件,從數據庫中刪除指定對象 - (BOOL) deleteByCondition:(NSString *) condition;   //更新對象屬性到數據庫中 -(BOOL) update:(BaseEntity *) info byKey:(id) key;   //插入指定對象到數據庫中 -(BOOL) insert:(BaseEntity *) info;   //插入指定對象到數據庫中,並返回最後插入的ID -(NSInteger) insert2:(BaseEntity *) info;   //查詢數據庫,檢查是否存在指定ID的對象 - (BaseEntity *) findById:(id) key;   //根據條件查詢數據庫,如果存在返回第一個對象 -(BaseEntity *) findSingle:(NSString *) condition;     //根據條件查詢數據庫,如果存在返回第一個對象 -(BaseEntity *) findSingle:(NSString *) condition orderBy:(NSString *) orderBy;   //根據條件查詢數據庫,並返回對象集合 - (NSArray *) find:(NSString *) condition;   //根據條件查詢數據庫,並返回對象集合 - (NSArray *) find:(NSString *) condition orderBy:(NSString *) orderBy;   //獲取表的全部數據 - (NSArray *) getAll;   //獲取表的全部數據 - (NSArray *) getAll:(NSString *) orderBy;   //獲取某字段數據字典列表 -(NSArray *) getFieldList:(NSString *) fieldName;   //獲取表的所有記錄數量 -(int) getRecordCount;   //根據條件,獲取表查詢的記錄數量 -(int) getRecordCount:(NSString *) condition;   //根據條件,判斷是否存在記錄 -(BOOL) isExistRecord:(NSString *)condition;   //查詢數據庫,檢查是否存在指定鍵值的對象 -(BOOL) isExist:(NSString *)fieldName value:(id) value;   //根據主鍵和字段名稱,獲取對應字段的內容 -(NSString *) getFieldValue:(NSString *)key fieldName:(NSString *)fieldName;   //執行SQL查詢語句,返回查詢結果的所有記錄的第一個字段,用逗號分隔。 -(NSString *) sqlValueList:(NSString *)query;   #pragma 數據庫初始化函數及關閉操作   //根據SQLite數據庫地址初始化數據庫 -(id) initWithPath:(NSString *)filePath;   //根據SQLite數據庫名稱初始化數據庫 -(id) initWithFileName:(NSString *)fileName;   // 關閉連接 -(void) close;   @end 復制代碼 和我的.NET框架裡面的數據訪問層設計一樣,數據訪問基類已經封裝了大多數的數據訪問操作,因此各個表的數據訪問對象,它的代碼就可以很簡潔了。從上面的基類接口設計可以看到,裡面一些實體類返回函數或者列表返回函數,都使用了BaseEntity作為對象,我們具體在起子類使用的時候,把它返回的對象再一次轉換即可。對於數據庫訪問基類,我們以一個返回集合的接口實現來分析。   復制代碼 - (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; //默認初始化為空     while ([rs next]) {         info = [self rsToEntity:rs];         [array addObject:info];     }     [rs close];          return array; } 復制代碼 上面代碼使用了參數化的SQL語句進行查詢,並且,對返回的數據庫的ResultSet進行轉換為實體類。   info = [self rsToEntity:rs]; 由於基類封裝了大多數的數據庫操作函數,因此數據訪問層的具體表的實現類,可以很簡潔,但是已經具備了常見的CRUD操作,以及一些分頁查詢等復雜的數據操作功能。   復制代碼 // //  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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved