iOS-FMDB改進(jìn)方案YIIFMDB:直接操作Model,純面向?qū)ο?,不需要?xiě)sql語(yǔ)句

我在寫(xiě)UDUserDefaultsModel(文章鏈接,github)這個(gè)庫(kù)時(shí)曾經(jīng)立下一個(gè)flag:要寫(xiě)一個(gè)基于model來(lái)存取數(shù)據(jù)庫(kù)的庫(kù),最近剛離職,所以就整合了一下,希望大家多多支持。

在iOS開(kāi)發(fā)過(guò)程當(dāng)中,難免用到數(shù)據(jù)庫(kù),以FMDB居多。以下是一個(gè)根據(jù)年齡篩選數(shù)據(jù)的sql語(yǔ)句:

select * from Student where age > 10 and age < 20 or age > 30 order by age desc limit 20

這樣寫(xiě)其實(shí)沒(méi)什么問(wèn)題,但是在我個(gè)人看來(lái)難以接受,字符串看起來(lái)太別扭。比如我再添加一個(gè)條件,那么就需要修改整個(gè)字符串了。

如果可以很好的控制sql語(yǔ)句,將大大提高編程效率。為此,YIIFMDB就改善了這個(gè)缺陷:純面向?qū)ο?,直接操作Model,完全不需要寫(xiě)sql語(yǔ)句。

其靈感源自于php的Yii 2架構(gòu),因?yàn)槲以诳磒hp代碼當(dāng)中,我發(fā)現(xiàn)根本就看不到sql語(yǔ)句,而php程序猿也說(shuō):“我們的工作就是操作數(shù)據(jù)庫(kù),但是卻不寫(xiě)sql語(yǔ)句”。

以下是YIIFMDB詳細(xì)用法:
YIIFMDB有兩個(gè)類(lèi):YIIFMDB和YIIParameters。其中YIIFMDB封裝了數(shù)據(jù)庫(kù)相關(guān)的操作,比如增刪改查之類(lèi),而YIIParameters則封裝了where之后的參數(shù),比如上段代碼當(dāng)中的:

age > 10 and age < 20 or age > 30 order by age desc limit 20

就可以在YIIParameters當(dāng)中完成。

接下來(lái)逐一介紹YIIParameters類(lèi)和YIIFMDB類(lèi)的使用:

YIIParameters類(lèi)

sql語(yǔ)句當(dāng)中where之后的參數(shù)基本上由以下模塊構(gòu)成:

  • and(與操作)
  • or(或操作)
  • order by(排序)
  • limit(數(shù)量限制)

其中的andor又要配置“>,<,=,>=,<=,!=,like”關(guān)系,order by又有“ase,dese”的排序操作。

YIIParameters這個(gè)類(lèi)就包含了以上所有元素。以上面的where之后的sql語(yǔ)句為例,具體用法如下:

// 初始化YIIParameters
YIIParameters *parameters = [[YIIParameters alloc] init];
// 執(zhí)行and操作,將age限制在10-20之間
// age > 10,YIIParametersRelationTypeGreaterThan標(biāo)志">"
[parameters andWhere:@"age" value:@"10" relationType:YIIParametersRelationTypeGreaterThan];  
// age < 20,YIIParametersRelationTypeLessThan標(biāo)志"<"
[parameters andWhere:@"age" value:@"20" relationType:YIIParametersRelationTypeLessThan];
// 以上是and,也就是形成的sql語(yǔ)句為: age > 10 and age < 20
// 執(zhí)行or操作,將age限制在age > 30 以上
[parameters orWhere:@"age" value:@"30" relationType:YIIParametersRelationTypeGreaterThan];
// 根據(jù)age進(jìn)行降序排列
// YIIParametersOrderTypeDesc表示降序"desc",YIIParametersOrderTypeAsc
[parameters orderByColumn:@"age" orderType:YIIParametersOrderTypeDesc];
// 將數(shù)據(jù)的個(gè)數(shù)限制在20個(gè)
parameters.limitCount = 20;

配置完畢,驗(yàn)證其是否配置正確,那么可以調(diào)用一下方法就行了:

NSLog(@"where參數(shù)為:%@", parameters.whereParameters);

當(dāng)然,如果參數(shù)都沒(méi)法配置了,則可以設(shè)置whereParameters。而對(duì)于YIIParameters更詳細(xì)的解釋請(qǐng)參考 YIIFMDB中的YIIParameters.h。

YIIFMDB類(lèi)

YIIParameters用來(lái)配置sql語(yǔ)句當(dāng)中where之后的參數(shù),而YIIFMDB類(lèi)則是對(duì)數(shù)據(jù)庫(kù)操作的進(jìn)一步封裝,具體如下:

獲取YIIFMDB單例

YIIFMDB *db = [YIIFMDB shareDatabase]; // 推薦使用
// 或者
YIIFMDB *db = [YIIFMDB shareDatabaseForName:@"ABC.sqlite" path:path]; // 自定義數(shù)據(jù)庫(kù)名字和路徑,在第一次實(shí)例的時(shí)候傳入,以后使用上面方法即可。

主鍵的字段

@property (nonatomic, readonly, copy) NSString *primaryKey; // 返回"yii_pkID",我自己在創(chuàng)建數(shù)據(jù)庫(kù)是配置的主鍵字段

是否打印log

@property (nonatomic, assign) BOOL shouldOpenDebugLog; // 默認(rèn)為NO,設(shè)為YES,會(huì)在控制器后臺(tái)打印數(shù)據(jù)庫(kù)操作相關(guān)的一些信息

創(chuàng)建一張表

[[YIIFMDB shareDatabase] createTableWithModelClass:[LCPersonModel class] excludedProperties:nil tableName:@"Person"];

此方法是創(chuàng)建一張名為@"Person"表,并且,表里面的字段也就是LCPersonModel里面的屬性,字段的數(shù)據(jù)類(lèi)型也對(duì)應(yīng)LCPersonModel里面的數(shù)據(jù)類(lèi)型

插入一條數(shù)據(jù)(增)

  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];  //插入一條數(shù)據(jù)
  [db insertWithModels:@[model] tableName:tableName];     // 批量插入數(shù)據(jù)

刪除數(shù)據(jù)(刪)

-(BOOL)deleteFromTable:(NSString * _Nonnull)tableName whereParameters:(YIIParameters *)parameters; // 根據(jù)參數(shù)刪除一條數(shù)據(jù),YIIParameters參考上面
-(BOOL)deleteAllDataFromTable:(NSString * _Nonnull)tableName; // 刪除表中的所有數(shù)據(jù)

 YIIFMDB *db = [YIIFMDB shareDatabase];
 YIIParameters *parameters = [[YIIParameters alloc] init];
 // db.primaryKey 是數(shù)據(jù)庫(kù)的主鍵,這條語(yǔ)句意思是刪除主鍵 = 1的那條數(shù)據(jù)
 [parameters andWhere:db.primaryKey value:@"1" relationType:YIIParametersRelationTypeEqualTo];
 [db deleteFromTable:tableName whereParameters:parameters];

更改數(shù)據(jù)(改)

-(BOOL)updateTable:(NSString * _Nonnull)tableName dictionary:(NSDictionary * _Nonnull)dictionary whereParameters:(YIIParameters *)parameters; // 更新一條數(shù)據(jù)

  YIIFMDB *db = [YIIFMDB shareDatabase];
  YIIParameters *parameters = [[YIIParameters alloc] init];
  // 參數(shù)設(shè)置為主鍵 = 10
  [parameters andWhere:db.primaryKey value:@"10" relationType:YIIParametersRelationTypeEqualTo];
  // 將主鍵為10的那條數(shù)據(jù)的name更改為monkey
  [db updateTable:tableName dictionary:@{@"name": @"monkey"} whereParameters:parameters];

查詢(xún)數(shù)據(jù)

-(NSArray *)queryFromTable:(NSString * _Nonnull)tableName model:(Class _Nonnull)modelClass whereParameters:(YIIParameters *)parameters; // 根據(jù)YIIParameters條件從表為tableName的查詢(xún)數(shù)據(jù)

  YIIFMDB *db = [YIIFMDB shareDatabase];
  YIIParameters *parameters = [[YIIParameters alloc] init];
  [parameters andWhere:db.primaryKey value:@"5" relationType:YIIParametersRelationTypeLessThan];
  NSLog(@"主鍵小于5的數(shù)據(jù):%@", [db queryFromTable:tableName model:[LCPersonModel class] whereParameters:parameters]);

除了增刪改查之外,YIIFMDB還提供了增加一個(gè)屬性,刪除一張表,獲取表中所有字段名,獲取表中數(shù)據(jù)個(gè)數(shù),表是否存在,求和,求平均值,最大值,最小值等功能,詳情請(qǐng)參考YIIFMDB的文檔。

線程安全操作(隊(duì)列和事務(wù))

由于FMDB本身就是是不安全的,上面的方法也是不安全的,為了保證其安全則需要結(jié)合隊(duì)列和事務(wù)操作,參考FMDB的隊(duì)列和事務(wù)。

-(void)inDatabase:(dispatch_block_t)block; // 將數(shù)據(jù)庫(kù)相關(guān)操作寫(xiě)在block里可保證線程安全

  YIIFMDB *db = [YIIFMDB shareDatabase];
   [db inDatabase:^{
       // 增刪改查放在此代碼塊里執(zhí)行則可以保證線程安全
   }];

-(void)inTransaction:(void(^)(BOOL *rollback))block; // 在block里寫(xiě)入代碼可執(zhí)行回滾操作

  YIIFMDB *db = [YIIFMDB shareDatabase];
  [db inTransaction:^(BOOL *rollback) {
  // 如果某一個(gè)操作失誤,則可以執(zhí)行回滾操作
  BOOL isSuccess = YES;   // 數(shù)據(jù)庫(kù)操作是否操作成功
  if (!isSuccess) {
      *rollback = YES;  //  回滾操作
                    
      return ;
     }
  }];

這里還有兩個(gè)缺陷:

  • 未支持聯(lián)表查詢(xún)
  • 未支持Model當(dāng)中套Model的插入。

如果是聯(lián)表查詢(xún)的話,那么需要獲取到YIIFMDB單例的"currentDatabase"來(lái)實(shí)現(xiàn)聯(lián)表查詢(xún),而Model套Model的,則最好是創(chuàng)建兩張表。

目前YIIFMDB已支持Cocoapods,地址:Github。(不要吝嗇你的star)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容