JYSqlModel是一個高效的 model、sqlite數(shù)據(jù)的轉(zhuǎn)換工具撕彤。在 JYSqlModel,每一條數(shù)據(jù)庫的數(shù)據(jù)都會被當做一個 model,所以當你對 model 執(zhí)行相應(yīng)的增刪改查操作時游桩,即對數(shù)據(jù)庫進行著增刪改查操作,這意味著你不再需要記得什么字段耐朴,什么約束借卧,甚至可以不再使用 sql 語句來操作數(shù)據(jù)庫!
JYSqlModel 依賴于庫FMDB隔箍,使用前請保證你的項目中有這個庫谓娃。
JYSqlModel 的思路來源來自于YYModel
使用前請將JYSqlModel
和JYClassInfo
的 .h 和 .m 文件,放到工程中蜒滩。
創(chuàng)建表
在 JYSqlModel 中滨达,一個 model 對應(yīng)于一個表。首先俯艰,你需要給這個表確定好一個名字捡遍,所以你必須在 model 內(nèi)重載 JYSqlModel 的類方法+ (nonnull NSString *)tbName;
。注意這個名字不能重復(fù)重復(fù)竹握。
系統(tǒng)會在啟動的時候画株,會根據(jù) model 結(jié)構(gòu)創(chuàng)建相應(yīng)的表。表中字段(column)與 model 屬性是一一對應(yīng)的啦辐,在默認情況下谓传,字段名字即是屬性名字,當然你也可以使用協(xié)議中的方法自定義字段名芹关,這個后面會詳細講续挟。字段的類型會根據(jù)屬性的類型分成不同的類型,目前只支持下表中的幾種類型:
字段類型 | 描述 | 對應(yīng)屬性類型 |
---|---|---|
integer | 整型數(shù) | c的整型侥衬,NSNumber |
real | 浮點數(shù) | c的浮點型诗祸,NSDecimalNumber |
text | 文本 | NSString跑芳,NSMutableString,NSURL |
blob | 二進制數(shù)據(jù) | NSData直颅,NSMutableData |
date | 日期 | NSDate |
bool | 布爾值 | c的bool |
unknow | 除上面所以博个,會報錯 | 除上面所有 |
如果你的類型不是上面支持的幾種類型之一,那么就會被歸為 unkonw 類型功偿,隨即就會報錯盆佣。這樣做的原因一方面是因為自己的知識不夠豐富,不知道怎么處理其它的類型械荷,另一方面避免復(fù)雜類型引起不可預(yù)料的錯誤罪塔。在后期的話可能還會支持 NSArray 等容器類型。
下面是一個簡單的例子:
@interface Student : JYSqlModel
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *school;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, strong) NSDate *birthDay;
@end
@implementation Student
+ (NSString *)tbName
{
return @"sudent";
}
@end
下面是創(chuàng)建相應(yīng)表的 sql:
create table if not exists sudent (school text ,age integer ,birthDay date ,name text ,height real)
是不是很簡單养葵,你只需要新建一個JYSqlModel
的子類征堪,并給它指定一個表名,就能自動的創(chuàng)建一個表关拒。
增
JYSqlModel 提供了以下幾種方法來幫助你將 model 寫入數(shù)據(jù)庫:
// 1
+ (BOOL)addModel:(nonnull __kindof JYSqlMode *)model;
// 2
+ (BOOL)addModels:(nonnull NSArray<__kindof JYSqlMode *> *)models;
// 3
- (BOOL)addToSql;
方法1和方法2類似佃蚜,都是使用類方法來添加 model 到數(shù)據(jù)庫中。需要注意的是着绊,model 的類需要跟類一致谐算,否則會添加失敗。
方法3是實例方法归露。添加成功會返回 YES洲脂,否則返回 NO
刪
JYSqlModel 提供了以下幾種方法來幫助你將 model 從數(shù)據(jù)庫中刪除:
// 1
+ (BOOL)deleteModelBySql:(nonnull NSString *)sql;
// 2
+ (BOOL)deleteModelByPrimaryKey:(NSString *)primaryKey value:(NSInteger)value;
// 3
+ - (BOOL)deleteFromSql;
方法1的話需要你自己寫刪除 sql,適用于刪除語句比較簡單或者批量刪除的時候剧包。你可以在子類中恐锦,根據(jù)這個方法封裝一個更簡單的方法。舉個例子:
@interface Student : JYSqlMode
+ (BOOL)deleteModeByPKValue:(NSInteger)value;
@end
@implementation JYPerson
+ (BOOL)deleteModeByPKValue:(NSInteger)value {
NSString *sql = [NSString stringWithFormat:@"delete from tbName where pk = %zd", value];
[JYSonModel deleteModelBySql:sql];
}
@end
現(xiàn)在你只需要一個pk值就能刪除數(shù)據(jù)庫記錄了疆液。當然你也可以封裝一個實例方法一铅,這樣連參數(shù)都不需要了。
方法2需要你指定一個主鍵名字以及主鍵值來刪除相應(yīng)記錄堕油。類似于方法1潘飘,你也可以根據(jù)該方法封裝一個更簡便的方法!
方法3不需要你提供什么參數(shù)掉缺,使用起來更簡單卜录,但是如果對應(yīng)表中沒有主鍵,該刪除方法就會失敗眶明,因為無法定位到具體到某一條記錄艰毒。
改
JYSqlModel 提供了以下幾種方法來幫助你更新數(shù)據(jù)庫中的記錄:
// 1
+ (BOOL)updateModelBySql:(NSString *)sql;
// 2
+ (BOOL)updateModel:(nonnull __kindof JYSqlMode *)model primaryKey:(NSString *)primaryKey value:(NSInteger)value;
方法1的話需要你自己提供更新 sql,適用于更新字段比較少或者批量更新的時候赘来。
方法2需要你提供一個主鍵來確定是哪條記錄现喳,以便更新相應(yīng)數(shù)據(jù)。該方法將更新除主鍵和autoincrement以外所有的字段犬辰,適用于更新字段比較多的情況嗦篱。
查
JYSqlModel 提供了以下幾種方法來幫助你查找數(shù)據(jù)庫中的記錄:
// 1
+ (nullable NSArray<__kindof JYSqlMode *> *)findModelsBySql:(nonnull NSString *)sql;
// 2
+ (nullable NSArray<__kindof JYSqlMode *> *)findAllModels;
方法1需要你自己提供查找 sql,返回結(jié)果將以 model 數(shù)組返回幌缝。
方法2將會查找出表中所有的記錄灸促,以 model 數(shù)組的形式返回。
數(shù)據(jù)遷移
在項目更新中涵卵,如果我們需要增加浴栽、刪除 model 中的某些屬性,或者改變屬性的類型要怎么辦呢轿偎?
很簡單典鸡,你只需要對 model 進行修改,在項目運行時坏晦,JYSqlMode 會檢測新 model 的結(jié)構(gòu)以及舊表的結(jié)構(gòu)萝玷,來判斷是否需要進行數(shù)據(jù)遷移。
所謂的數(shù)據(jù)遷移
也就是昆婿,將舊表重命名球碉,根據(jù)新 model 的結(jié)構(gòu)新建一個表,然后將舊表的數(shù)據(jù)遷移到新的表中仓蛆。如此操作之后睁冬,新表的結(jié)構(gòu)與新 model 的結(jié)構(gòu)就一一對應(yīng)了,保證了你在執(zhí)行增刪改查操作時不會出錯看疙。
當然豆拨,也有一些情況下,可能你做了修改也不會觸發(fā)數(shù)據(jù)遷移能庆。例如辽装,如果僅僅是改變了字段的約束條件,那么是不會觸發(fā)數(shù)據(jù)遷移的相味。解決辦法最后面會給出拾积。
JYSqlMode
下面是協(xié)議JYSqlMode
的可選方法,幫助你執(zhí)行一些自定義操作:
// 1
+ (nullable NSDictionary<NSString *, id> *)jyCustomPropertyMapper;
// 2
+ (nullable NSDictionary<NSString *, NSDictionary *> *)jyCustomPropertyConstraint;
方法1幫助你實現(xiàn)自定義 屬性 -> 表字段名 的映射丰涉。舉個例子:
@interface Student : JYSqlMode <JYSqlMode>
@property NSString *name;
@property NSString *title;
@property NSInteger age;
@end
implementation Student
+ (nullable NSDictionary<NSString *, id> *)jyCustomPropertyMapper {
return @{
@"name" : @"fName",
@"title" : @"ftitle",
@"age" : @"fage"
}
}
@end
在相應(yīng)的表中拓巧,fName 將會對應(yīng)屬性 name,ftitle 將會對應(yīng)屬性 title一死,fage 將會對應(yīng)屬性 age
方法2幫助你實現(xiàn)自定義字段的約束條件肛度。目前僅支持以下幾種約束類型:
- JYColumnConstraintKeyNotNull -> not null
- JYColumnConstraintKeyDefault -> default
- JYColumnConstraintKeyDefaultValue -> 默認值,需要與 JYColumnConstraintKeyDefault 配套使用
- JYColumnConstraintKeyUnique -> unique
- JYColumnConstraintKeyPrimaryKey -> primary key
- JYColumnConstraintKeyAutoIncrement -> autoincrement
需要注意的是投慈,JYColumnConstraintKeyDefault 需要配合 JYColumnConstraintKeyDefaultValue 使用承耿,設(shè)置一個默認值冠骄。
舉個例子:
@interface Student : JYSqlModel <JYSqlModel>
@property (nonatomic, assign) NSInteger fid;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *school;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, strong) NSDate *birthDay;
@end
@implementation Student
+ (nullable NSDictionary<NSString *, NSDictionary *> *)jyCustomPropertyConstraint;
{
return @{
@"fid" : @{
JYColumnConstraintKeyPrimaryKey : @YES,
JYColumnConstraintKeyUnique : @YES
JYColumnConstraintKeyAutoIncrement : @YES
},
@"school" : @{
JYColumnConstraintKeyDefault : @YES,
JYColumnConstraintKeyDefaultValue : @"背背山小學(xué)"
}
};
}
@end
這樣子,你就定義了一個primary key unique autoincrement
的主鍵 fid加袋,以及一個default '背背山小學(xué)'
的字段 school凛辣。
@note
限于個人水平,JYSqlModel 肯定會在一些的問題职烧。也許你會奇怪明明按說明操作了扁誓,但沒有出現(xiàn)想要的結(jié)構(gòu)。下面我將總結(jié)一下使用時需要注意的地方:
- 已存在一個舊表蚀之,若只是修改了相應(yīng)字段的約束條件蝗敢,這些約束條件是不會立刻生效的。一個解決辦法是預(yù)留一個字段足删,當你需要更新表結(jié)構(gòu)的時候修改這個預(yù)留字段的名字
- 已存在一個舊表寿谴,如果你為它設(shè)置了一個主鍵,抱歉設(shè)置會失敗失受。解決方法參考第1條
- NSNumber類型的屬性會存儲到 integer 類型的字段中拭卿,如果想保存成浮點數(shù)的話,請將屬性類型改為 NSDecimalNumber 或者直接使用 C 的浮點類型 float, double等
- 如果你在運行時動態(tài)的為 model 新增了屬性贱纠,抱歉峻厚,表結(jié)構(gòu)也不會更新