用一个类根据Model属性生成SQL语句
想到寫這個的原因是我和我的一個朋友在寫一個開源項目的時候,我負責了數據庫的持久化存儲部分,結果他看到了我的數據庫數據存儲結構之后直接傻眼了,因為個人比較簡單粗暴,直接把一個數據Model歸檔成為二進制Data之后丟到了數據庫,然后取出來也可以偷偷懶,解檔就是一個模型Model啦,但是我的小伙伴不樂意了,把我批評了一頓,說我吧數據庫的“檢索”價值都給寫沒了,好吧,我承認當時我聽得一臉懵逼,不過好像挺有道理?,不過按照他說的檢索價值,我想的話應該就是把數據存儲的更為清晰吧,那就要分更多的字段了【長長的SQL語句讓我在角落瑟瑟發抖?】,唉,個人真的非常懶,想到這些就頭疼,那么我們能不能用一個類根據Model屬性生成SQL語句呢?答案是肯定的,接著往下看吧!
SQLite背景:【SQL(Structured Query Language)結構語言】SQLite是目前主流的嵌入式關系型數據庫,其主要的特點的就是輕量級,跨平臺,當前很多嵌入式操作系統都將其作為數據庫的首先。它是基于C語言開發的數據庫!所以我們需要通過hi用c語言語法進行數據庫的操作和訪問!
**思路:**SQL語句首先是建表,建表包含了字段名,表名,字段對應的存儲類型,那么我們就要先來熟悉一下我們的七種基本數據類型以及那些常量類型到了數據庫中是什么類型吧,這樣才能和每一個字段對應上,既能夠達到存儲目的,又能節省空間
SQL數據庫中的存儲類型【比較多,但是請耐心看完,并不復雜】SQlite數據庫存儲類型
思路演變:我們既然想要用一個類來根據Model屬性生成SQL,那么這個類肯定應該是普遍適用的,否則就沒有多大意義了,那么我們肯定就要獲取這個Model所有的屬性以及屬性對應的類型,然后根據這些屬性名字來生成數據庫中對應的字段,屬性的類型經過處理之后變成數據庫中的存儲類型,很明顯,我們又要用運行時了!
在了解了存儲類型之后我們就要來真正的動刀了,首先我們要通過運行時來解析我們通常所用的數據類型在運行時中是怎么表示的;這里我就不多說了,直接貼方法,怎么根據運行時獲取一個類所對應的屬性和屬性類型:
/** 根據要存儲進入數據庫中的類,獲取該類的屬性 以及 該類存儲進入數據庫后屬性對應的 數據庫存儲類型 @param class 要存儲的類 */ - (void)disposePropertyWithClass:(Class)class { if (class && class != [NSObject class] && class != [MySqlStatementManager class]) { unsigned int outCount = 0; Ivar *ivars = class_copyIvarList(class, &outCount); for (int i = 0 ; i < outCount; i ++ ) { Ivar ivar = ivars[i]; //運行時獲取屬性名 NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)]; //去掉屬性名開頭中的下劃線 if ([key rangeOfString:@"_"].location == 0) { key = [key substringFromIndex:1]; } //運行時獲取類型 NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)]; NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"@/:;()¥「」"、[]{}#%-*+=_\\|~<>$€^?’@#$%^&*()_+’\""]; type = [type stringByTrimmingCharactersInSet:set]; if (!self.propertyDic[type]) { //如果屬性類型不是七種基本數據類型,也不是int short 等常量類型,那么顯示如下LOG提示 NSLog(@"數據庫不支持%@類中為%@類型的%@屬性存儲,該屬性數據將會丟失,請重新建立該類屬性類型",NSStringFromClass(class),key,type); }else{ // 將屬性中的類型和數據庫中的一些類型進行配對 NSString *sqlSaveType = self.propertyDic[type]; [self.propertyListDic setValue:sqlSaveType forKey:key]; } } free(ivars); } } 復制代碼這里用到了self.propertyDic? 和? self.propertyListDic,解釋一下: self.propertyDic??這個字典是用來將我們常用的所有類型按照:我們Model中各個屬性用的類型【KEY】----各個屬性應該對應的數據庫存儲類型【Value】先前就已經初始化好的一個固定不變的字典,意義就是根據我們用的類型來取到數據庫中這個類型對應的存儲類型 self.propertyListDic??這個字典是用來記錄我們已經處理分析好的一些屬性所應該對應的數據庫存儲類型,那么它最后的形式就是:我們Model中各個屬性名稱【KEY】----數據庫中各個屬性的存儲類型【Value】
然后我分析之后我們的self.propertyDic應該是這樣:
// 結合運行時獲取model對應的屬性類型 ( KEY ),然后這些類型將在數據庫中以以下 (Value) 類型進行存儲 - (NSDictionary *)propertyDic { if (_propertyDic == nil) { _propertyDic = @{@"NSString" : @"varchar(1024)", @"NSMutableString" : @"varchar(1024)", @"NSArray" : @"blob", @"NSMutableArray" : @"blob", @"NSDictionary" : @"blob", @"NSMutableDictionary" : @"blob", @"NSData" : @"blob", @"NSMutableData" : @"blob", @"NSDate" : @"datetime", @"NSNumber" : @"varchar(1024)", @"c" : @"varchar(128)",? ? // 可能為BOOL 類型或者 char 類型 @"i" : @"int",? ? // Int 類型 @"s" : @"int",? ? // Short 類型 @"f" : @"float",? ? // Float 類型 @"d" : @"numeric",? ? // Double 類型 @"q" : @"int",? ? // Long 類型 @"B" : @"bit",? ? // iphone上BOOL類型運行時獲取的類型名為 B, mac環境獲取的是 ‘c’ @"" : @"",}; } return _propertyDic; } 復制代碼**解釋說明:**可能已經有細心的小伙伴發現了,我的_propertyDic中設置的數組存儲類型為blob【二進制大數據】,我知道這樣做不妥,但是SQLite是不支持數組的存儲的,而儲存數組我認為的最佳方法是再建一張表,將這個數組用這一張表存起來,這其中又會涉及到數據庫主鍵【PRIMARY KEY】的知識,取出數據時再通過聯表查詢才能取出來一個我們所需要的數據模型【不知道有沒有對數據庫很熟悉的小伙伴有不同的看法,歡迎來一起交流】,這還只是model中只有一個數組的情況下,如果數組中存儲的數組,那就更尷尬了,可能一個Model要對應N張表聯查才能取出來完整的數據,當然,數據庫也是不支持OC字典存儲的,所以剩下的場景大家自己腦補吧
**關于存儲類型的結論:**綜上情景的分析,為了偷懶【請原諒我如此直白】,我選擇了直接將數組歸檔為二進制數據存儲進入數據庫?,有更好方法的歡迎評論區交流
那么繼續吧,上面我們已經通過_propertyDic和_propertyListDic分析出了Model中存在的所有屬性名稱以及該屬性應該在數據庫中以何種類型存儲,接下來就是生成SQL字符串了
因為SQL語句眾多,這里我以建表的SQL為例,其他的大家可以自己去思考怎么生成SQL:
#pragma mark - 建表 - (NSString *)greatTableWithTableName:(NSString *)tableName andClass:(Class)modelClass {[self disposePropertyWithClass:modelClass];__block NSString *greatSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(",tableName];[self.propertyListDic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {greatSql = [NSString stringWithFormat:@"%@%@ %@,",greatSql,key, obj];}];greatSql = [greatSql substringToIndex:greatSql.length - 1];//補上結尾一個括號greatSql = [NSString stringWithFormat:@"%@)",greatSql];return greatSql; } 復制代碼調用如下:
MySqlStatementManager *manger = [[MySqlStatementManager alloc] init];NSString *sql = [manger greatTableWithTableName:@"測試" andClass:[TestModel class]];NSLog(@"TestModel 對應的數據庫 建表語句如下 %@",sql); 復制代碼轉載于:https://juejin.im/post/5b2b05faf265da59aa2d8e32
總結
以上是生活随笔為你收集整理的用一个类根据Model属性生成SQL语句的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ip地址详解,ip地址各种写法的意义,私
- 下一篇: Eclipse Collections: