iOS-FMDB改進方案YIIFMDB:直接操作Model,純面向物件,不需要寫sql語句
我在寫UDUserDefaultsModel(文章連結,ofollow,noindex">github )這個庫時曾經立下一個flag:要寫一個基於model來存取資料庫的庫,最近剛離職,所以就整合了一下,希望大家多多支援。
在iOS開發過程當中,難免用到資料庫,以FMDB居多。以下是一個根據年齡篩選資料的sql語句:
select * from Student where age > 10 and age < 20 or age > 30 order by age desc limit 20
這樣寫其實沒什麼問題,但是在我個人看來難以接受,字串看起來太彆扭。比如我再新增一個條件,那麼就需要修改整個字串了。
如果可以很好的控制sql語句,將大大提高程式設計效率。為此,YIIFMDB 就改善了這個缺陷:純面向物件,直接操作Model,完全不需要寫sql語句 。
其靈感源自於php的Yii 2架構 ,因為我在看php程式碼當中,我發現根本就看不到sql語句,而php程式猿也說:“我們的工作就是操作資料庫,但是卻不寫sql語句 ”。
以下是YIIFMDB 詳細用法:
YIIFMDB 有兩個類:YIIFMDB 和YIIParameters。其中YIIFMDB 封裝了資料庫相關的操作,比如增刪改查之類,而YIIParameters則封裝了where之後的引數,比如上段程式碼當中的:
age > 10 and age < 20 or age > 30 order by age desc limit 20
就可以在YIIParameters當中完成。
接下來逐一介紹YIIParameters類和YIIFMDB 類的使用:
YIIParameters類
sql語句當中where之後的引數基本上由以下模組構成:
- and(與操作)
- or(或操作)
- order by(排序)
- limit(數量限制)
其中的and 和or 又要配置“>,<,=,>=,<=,!=,like”關係,order by 又有“ase,dese”的排序操作。
YIIParameters這個類就包含了以上所有元素。以上面的where之後的sql語句為例,具體用法如下:
// 初始化YIIParameters YIIParameters *parameters = [[YIIParameters alloc] init]; // 執行and操作,將age限制在10-20之間 // age > 10,YIIParametersRelationTypeGreaterThan標誌">" [parameters andWhere:@"age" value:@"10" relationType:YIIParametersRelationTypeGreaterThan]; // age < 20,YIIParametersRelationTypeLessThan標誌"<" [parameters andWhere:@"age" value:@"20" relationType:YIIParametersRelationTypeLessThan]; // 以上是and,也就是形成的sql語句為: age > 10 and age < 20 // 執行or操作,將age限制在age > 30 以上 [parameters orWhere:@"age" value:@"30" relationType:YIIParametersRelationTypeGreaterThan]; // 根據age進行降序排列 // YIIParametersOrderTypeDesc表示降序"desc",YIIParametersOrderTypeAsc [parameters orderByColumn:@"age" orderType:YIIParametersOrderTypeDesc]; // 將資料的個數限制在20個 parameters.limitCount = 20;
配置完畢,驗證其是否配置正確,那麼可以呼叫一下方法就行了:
NSLog(@"where引數為:%@", parameters.whereParameters);
當然,如果引數都沒法配置了,則可以設定whereParameters 。而對於YIIParameters更詳細的解釋請參考YIIFMDB 中的YIIParameters.h 。
YIIFMDB 類
YIIParameters用來配置sql語句當中where之後的引數,而YIIFMDB 類則是對資料庫操作的進一步封裝,具體如下:
獲取YIIFMDB 單例
YIIFMDB *db = [YIIFMDB shareDatabase]; // 推薦使用 // 或者 YIIFMDB *db = [YIIFMDB shareDatabaseForName:@"ABC.sqlite" path:path]; // 自定義資料庫名字和路徑,在第一次例項的時候傳入,以後使用上面方法即可。
主鍵的欄位
@property (nonatomic, readonly, copy)NSString *primaryKey; // 返回"yii_pkID",我自己在建立資料庫是配置的主鍵欄位
是否列印log
@property (nonatomic, assign) BOOL shouldOpenDebugLog;// 預設為NO,設為YES,會在控制器後臺列印資料庫操作相關的一些資訊
建立一張表
[[YIIFMDB shareDatabase] createTableWithModelClass:[LCPersonModel class] excludedProperties:nil tableName:@"Person"];
此方法是建立一張名為@"Person"表,並且,表裡面的欄位也就是LCPersonModel裡面的屬性,欄位的資料型別也對應LCPersonModel裡面的資料型別
插入一條資料(增)
LCPersonModel *model = [[LCPersonModel alloc] init]; model.name = [NSString stringWithFormat:@"lc%d", (arc4random() % 100)]; model.gender = arc4random() % 2; model.age = arc4random() % 80; model.floatNumber = (arc4random() % 20) / 100.0; model.doubleNumber = (arc4random() % 20) / 100.0; model.isMan = arc4random() % 2; model.number = @(arc4random() % 10); YIIFMDB *db = [YIIFMDB shareDatabase]; BOOL isSuccess = [db insertWithModel:model tableName:tableName];//插入一條資料 [db insertWithModels:@[model] tableName:tableName];// 批量插入資料
刪除資料(刪)
-(BOOL)deleteFromTable:(NSString * _Nonnull)tableName whereParameters:(YIIParameters *)parameters; // 根據引數刪除一條資料,YIIParameters參考上面
-(BOOL)deleteAllDataFromTable:(NSString * _Nonnull)tableName; //刪除表中的所有資料
YIIFMDB *db = [YIIFMDB shareDatabase]; YIIParameters *parameters = [[YIIParameters alloc] init]; // db.primaryKey 是資料庫的主鍵,這條語句意思是刪除主鍵 = 1的那條資料 [parameters andWhere:db.primaryKey value:@"1" relationType:YIIParametersRelationTypeEqualTo]; [db deleteFromTable:tableName whereParameters:parameters];
更改資料(改)
-(BOOL)updateTable:(NSString * _Nonnull)tableName dictionary:(NSDictionary * _Nonnull)dictionary whereParameters:(YIIParameters *)parameters; // 更新一條資料
YIIFMDB *db = [YIIFMDB shareDatabase]; YIIParameters *parameters = [[YIIParameters alloc] init]; // 引數設定為主鍵 = 10 [parameters andWhere:db.primaryKey value:@"10" relationType:YIIParametersRelationTypeEqualTo]; // 將主鍵為10的那條資料的name更改為monkey [db updateTable:tableName dictionary:@{@"name": @"monkey"} whereParameters:parameters];
查詢資料
-(NSArray *)queryFromTable:(NSString * _Nonnull)tableName model:(Class _Nonnull)modelClass whereParameters:(YIIParameters *)parameters; // 根據YIIParameters條件從表為tableName的查詢資料
YIIFMDB *db = [YIIFMDB shareDatabase]; YIIParameters *parameters = [[YIIParameters alloc] init]; [parameters andWhere:db.primaryKey value:@"5" relationType:YIIParametersRelationTypeLessThan]; NSLog(@"主鍵小於5的資料:%@", [db queryFromTable:tableName model:[LCPersonModel class] whereParameters:parameters]);
除了增刪改查之外,YIIFMDB 還提供了增加一個屬性,刪除一張表,獲取表中所有欄位名,獲取表中資料個數,表是否存在,求和,求平均值,最大值,最小值 等功能,詳情請參考YIIFMDB 的文件。
執行緒安全操作(佇列和事務)
由於FMDB本身就是是不安全的,上面的方法也是不安全的,為了保證其安全則需要結合佇列和事務操作,參考FMDB的佇列和事務。
-(void)inDatabase:(dispatch_block_t)block;// 將資料庫相關操作寫在block裡可保證執行緒安全
YIIFMDB *db = [YIIFMDB shareDatabase]; [db inDatabase:^{ // 增刪改查放在此程式碼塊裡執行則可以保證執行緒安全 }];
-(void)inTransaction:(void(^)(BOOL *rollback))block; // 在block裡寫入程式碼可執行回滾操作
YIIFMDB *db = [YIIFMDB shareDatabase]; [db inTransaction:^(BOOL *rollback) { // 如果某一個操作失誤,則可以執行回滾操作 BOOL isSuccess = YES;// 資料庫操作是否操作成功 if (!isSuccess) { *rollback = YES;//回滾操作 return ; } }];
這裡還有兩個缺陷:
- 未支援聯表查詢
- 未支援Model當中套Model的插入。
如果是聯表查詢的話,那麼需要獲取到YIIFMDB 單例的"currentDatabase"來實現聯表查詢,而Model套Model的,則最好是建立兩張表。