概述
移动app端数据库的创建,在思想上有两种方式:
a.创建通用表(id, time, data), time是操作时间,data是存放json数据的字符串(把数据转json字符串存放)。这样的好处是不需要想着数据库升级的问题,但若是有查询类似点赞数量就感觉不太适合了。
b.创建正常表,有什么字段写什么字段。但这样会涉及到表字段的增加,也就是数据库的升级。
参考文档:
a:这是唐巧大神的文章 通用表
b:这是一位高手的文章 正常表
正文
我今天说的是b种数据库。解决了app切换账号数据库的更换和数据库版本升级问题。
总体思想:
1.切换账号:例如手机号登录,以手机号来命名数据库,这样解决不同手机登录,来访问不同的数据库。还有种思想是一个数据库,表不同,某个功能表前加前缀来区分,但是我想象感觉有点麻烦,去升级和添加字段的时候。
2.版本升级:它也有两种思路,一种是直接sql命令添加需要的字段名和类型。另一种是创建新表,把老表数据拷贝到新表里去,然后删去老表,更改新表的名字。
代码展示
这是我写的 demo
欢迎点赞收藏和批评。每个语言都博大精深我们应该谦虚向学。
IGFMDB.h 文件
#import <Foundation/Foundation.h>
#import "IGParameters.h"
NS_ASSUME_NONNULL_BEGIN
// 数据库支持的类型(如果不满足条件以下条件,那么在后续会增加)
typedef NS_ENUM(NSUInteger, IGFMDBValueType) {
IGFMDBValueTypeString, // 字符串
IGFMDBValueTypeInteger, // 整型,长整型,bool值 都是integer
IGFMDBValueTypeFloat, // 浮点型,double
IGFMDBValueTypeData, // 二进制数据
};
// 数学运算的类型
typedef NS_ENUM(NSUInteger, IGFMDBMathType) {
IGFMDBMathTypeSum, // 总和
IGFMDBMathTypeAvg, // 平均值
IGFMDBMathTypeMax, // 最大值
IGFMDBMathTypeMin, // 最小值
};
@interface IGFMDB : NSObject
#pragma mark - 初始化
+ (instancetype) shareDatabase; //会默认创建一个db
- (void) createDBWithName:(NSString *)dbName;
- (void) createDBWithName:(NSString *)dbName path:(NSString *)dbPath;
- (void)upgradeDatabase:(NSString *)dbName;
#pragma mark - 创建表
/**
* 根据传入的Model去创建表(推荐使用此方法)
* @param modelClass
model的属性名称作为表的key值, 属性的value的类型也就是表里面的value的类型,如value可以是NSString,integer,float,bool等
* @param excludedProperties 被排除掉属性,这些属性被排除掉之后则不会存在数据库当中
* @param tableName 表名,不可以为nil
* @return 是否创建成功
*/
- (BOOL)createTableWithModelClass:(Class _Nonnull)modelClass
excludedProperties:(NSArray<NSString *> * _Nullable)excludedProperties
tableName:(NSString * _Nonnull)tableName;
#pragma mark - 插入数据
/**
* 插入一条数据(推荐使用)
* @param model 需要插入Model
* @param tableName 表名,不可以为nil
* @return 是否插入成功
*/
- (BOOL)insertWithModel:(id _Nonnull)model tableName:(NSString * _Nonnull)tableName;
/**
* 插入多条数据
* @param models 需要插入的存放Model的数组。其中必须要保证数组内的Model都是同一类型的Model
* @param tableName 表名,不可以为nil
* 在连续插入多条数据的时候,很有可能会出现插入不成功的情况,如果想要联调,请将shouldOpenDebugLog设为YES
*/
- (void)insertWithModels:(NSArray *)models tableName:(NSString * _Nonnull)tableName;
#pragma mark - 删除数据
/**
* 根据参数删除表中的数据
* @param tableName 表的名字
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数。
* @return 是否删除成功
*/
- (BOOL)deleteFromTable:(NSString * _Nonnull)tableName whereParameters:(IGParameters *)parameters;
/**
* 删除所有数据
* @param tableName 同上
* @return 同上
*/
- (BOOL)deleteAllDataFromTable:(NSString * _Nonnull)tableName;
#pragma mark - 更改数据
/**
* 根据参数删除表中的数据
* @param tableName 表的名字,不可以为nil
* @param dictionary 要更新的key-value.在我经验来看,更改典里部分数据
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数
*/
- (BOOL)updateTable:(NSString * _Nonnull)tableName dictionary:(NSDictionary * _Nonnull)dictionary whereParameters:(IGParameters *)parameters;
#pragma mark - 查询数据
/**
* 根据参数删除表中的数据
* @param tableName 表的名字,不可以为nil
* @param modelClass modelClass里属性的都当key拿值
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数
* @return 返回所有符合条件的数据
*/
- (NSArray *)queryFromTable:(NSString * _Nonnull)tableName model:(Class _Nonnull)modelClass whereParameters:(IGParameters *)parameters;
#pragma mark - 除去增删改查之外常用的功能
/**
* 表是否存在
* @param tableName 表的名字
* @return 表是否存在
*/
- (BOOL)existTable:(NSString * _Nonnull)tableName;
/**
* 为一个表增加字段
* @param tableName 表的名字
* @param column 要增加的字段
* @param type 增加的字段类型
* @return 是否添加成功
*/
- (BOOL)alterTable:(NSString * _Nonnull)tableName column:(NSString * _Nonnull)column type:(IGFMDBValueType)type;
/**
* 删除一张表
* @param tableName 表的名字
* @return 是否删除成功
*/
- (BOOL)dropTable:(NSString * _Nonnull)tableName;
/**
* 获取某一个表中所有的字段名
* @param tableName 表的名字
* @return 所有字段名
*/
- (NSArray<NSString *> *)getAllColumnsFromTable:(NSString * _Nonnull)tableName;
/**
* 获取表中有多少条数据
* @param tableName 表的名字
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数
* @return 数据的个数
*/
- (long long int)numberOfItemsFromTable:(NSString * _Nonnull)tableName whereParameters:(IGParameters * _Nullable)parameters;
/**
* 数学相关操作
* @param type 数学运算的type
* @param tableName 表的名字
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数
* @return 计算的值
*/
- (double)numberWithMathType:(IGFMDBMathType)type table:(NSString * _Nonnull)tableName column:(NSString * _Nonnull)column whereParameters:(IGParameters * _Nullable)parameters;
@end
NS_ASSUME_NONNULL_END
IGFMDB.m 文件
#import "IGFMDB.h"
#import <FMDB/FMDB.h>
#import <objc/runtime.h>
#ifdef DEBUG
#define debugLog(...) NSLog(__VA_ARGS__)
#define debugMethod() NSLog(@"%s", __func__)
#define debugError() NSLog(@"Error at %s Line:%d", __func__, __LINE__)
#else
#define debugLog(...)
#define debugMethod()
#define debugError()
#endif
#define PATH_OF_DOCUMENT [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
#define kDatabaseVersionKey @"YH_DBVersion" //数据库版本
static NSString * const DEFAULT_DB_NAME = @"database.sqlite";
static NSString * const ig_primary_key = @"primaryId"; // 主键
static NSString * const ig_sql_text = @"text"; // 字符串
static NSString * const ig_sql_real = @"real"; // 浮点型
static NSString * const ig_sql_blob = @"blob"; // 二进制
static NSString * const ig_sql_integer = @"integer"; // 整型
@interface IGFMDB ()
@property (strong, nonatomic) FMDatabaseQueue * dbQueue;
@property (nonatomic, assign) int currentDBVersion; //当要升级就给这个值赋值
@end
@implementation IGFMDB
{
// 保证创建sql语句时的线程安全
dispatch_semaphore_t _sqlLock;
}
- (void)close {
[_dbQueue close];
_dbQueue = nil;
}
// 校验表名
- (BOOL)checkTableName:(NSString *)tableName {
if (tableName == nil || tableName.length == 0 || [tableName rangeOfString:@" "].location != NSNotFound) {
debugLog(@"ERROR, table name: %@ format error.", tableName);
return NO;
}
return YES;
}
- (BOOL)isStringVaild:(id)object {
return [object isKindOfClass:[NSString class]] && ((NSString*)object).length > 0;
}
#pragma mark -单利,创建默认DB
+ (instancetype) shareDatabase {
static IGFMDB *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_instance == nil) {
_instance = [[IGFMDB alloc] init];
}
});
return _instance;
}
- (instancetype) init {
if (self = [super init]) {
_currentDBVersion = 0;
_sqlLock = dispatch_semaphore_create(1);
[self createDBWithName:DEFAULT_DB_NAME];
}
return self;
}
#pragma mark -创建DB方法
- (void) createDBWithName:(NSString *)dbName {
[self createDBWithName:dbName path:PATH_OF_DOCUMENT];
}
- (void) createDBWithName:(NSString *)dbName path:(NSString *)dbPath {
NSString *path = [dbPath stringByAppendingPathComponent:dbName];
debugLog(@"-----path: %@ \n-----",path);
if (_dbQueue) {
[self close];
}
_dbQueue = [FMDatabaseQueue databaseQueueWithPath:path];
}
#pragma mark -数据库升级模块
//这样写还是很好的, 不可以参数暴露在外面
- (void)upgradeDatabase:(NSString *)dbName
{
int dbVersion = [self getDBVersion:dbName];
if (_currentDBVersion > dbVersion) {
//debugLog(@"-----升级操作: 为student表 增加个sound------");
if ([self existTable:@"student"]) {
[self alterTable:@"student" column:@"sound" type:IGFMDBValueTypeData];
[self setDBVersion:_currentDBVersion dbName:dbName];
//debugLog(@"-----升级操作成功-----");
}
}
}
- (int)getDBVersion:(NSString *)dbName {
return (int)[[NSUserDefaults standardUserDefaults] integerForKey:kDatabaseVersionKey];
}
- (void)setDBVersion:(int)version dbName:(NSString *)dbName {
[[NSUserDefaults standardUserDefaults] setInteger:version forKey:kDatabaseVersionKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
#pragma mark -创建表
- (BOOL)createTableWithModelClass:(Class _Nonnull)modelClass excludedProperties:(NSArray<NSString *> * _Nullable)excludedProperties tableName:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) {
return NO;
}
IGLock(_sqlLock);
NSString *pkID = ig_primary_key;
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"create table if not exists %@ (%@ integer primary key",tableName, pkID];
IGUnLock(_sqlLock);
NSDictionary *properties = [self getPropertiesWithModel:modelClass]; //获取model的所有属性以及类型
for (NSString *key in properties) {
if ([excludedProperties containsObject:key]) {
continue;
}
[sqliteString appendFormat:@", %@ %@", key, properties[key]];
}
[sqliteString appendString:@")"];
__block BOOL res ;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
res = [db executeUpdate:sqliteString];
}];
return res;
}
#pragma mark - 插入数据
- (BOOL)insertWithModel:(id _Nonnull)model tableName:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) {
return NO;
}
if (model)
{
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"insert into %@ (", tableName];
NSArray *columns = [self getAllColumnsFromTable:tableName dbQueue:self.dbQueue isIncludingPrimaryKey:NO];
NSMutableArray *values = [NSMutableArray array];
for (int index = 0; index < columns.count; index++) {
[values addObject:@"?"];
}
[sqliteString appendFormat:@"%@) values (%@)", [columns componentsJoinedByString:@","], [values componentsJoinedByString:@","]];
IGUnLock(_sqlLock);
__block BOOL isSuccess ;
NSArray *arguments = [self getValuesFromModel:model columns:columns];
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString withArgumentsInArray:arguments];
}];
if (!isSuccess) {
debugLog(@"----插入失败----");
}
else {
debugLog(@"----插入成功----");
}
return isSuccess;
}
else {
return NO;
}
}
- (void)insertWithModels:(NSArray *)models tableName:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) return;
if (models && [models isKindOfClass:[NSArray class]] && models.count > 0)
{
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"insert into %@ (", tableName];
NSArray *columns = [self getAllColumnsFromTable:tableName dbQueue:self.dbQueue isIncludingPrimaryKey:NO];
NSMutableArray *values = [NSMutableArray array];
for (int index = 0; index < columns.count; index++) {
[values addObject:@"?"];
}
[sqliteString appendFormat:@"%@) values (%@)", [columns componentsJoinedByString:@","], [values componentsJoinedByString:@","]];
IGUnLock(_sqlLock);
for (id model in models) {
__block BOOL isSuccess;
NSArray *arguments = [self getValuesFromModel:model columns:columns];
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString withArgumentsInArray:arguments];
}];
if (!isSuccess) {
debugLog(@"----插入失败----");
}
}
}
else {
debugLog(@"----插入数据的数据源有误----");
}
}
#pragma mark - 删除数据
- (BOOL)deleteFromTable:(NSString * _Nonnull)tableName whereParameters:(IGParameters *)parameters {
if (![self checkTableName:tableName]) return NO;
if (![self isStringVaild:parameters.whereParameters]) {
debugLog(@"-----单条删除没有条件------");
return NO;
}
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"delete from %@", tableName];
if (parameters) {
[sqliteString appendFormat:@" where %@", parameters.whereParameters];
}
IGUnLock(_sqlLock);
__block BOOL isSuccess ;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString];
}];
if (!isSuccess) {
debugLog(@"----删除失败----");
}
return isSuccess;
}
- (BOOL)deleteAllDataFromTable:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) return NO;
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"delete from %@", tableName];
IGUnLock(_sqlLock);
__block BOOL isSuccess ;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString];
}];
if (!isSuccess) {
debugLog(@"----删除失败----");
}
return isSuccess;
}
#pragma mark - 更改数据
- (BOOL)updateTable:(NSString * _Nonnull)tableName dictionary:(NSDictionary * _Nonnull)dictionary whereParameters:(IGParameters *)parameters {
if (![self checkTableName:tableName]) return NO;
if (dictionary.allKeys.count <= 0) {
debugLog(@"----要更新的数据不能为nil----");
return NO;
}
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"update %@ set ", tableName];
NSMutableArray *values = [NSMutableArray array];
for (NSString *key in dictionary) {
if ([key isEqualToString:ig_primary_key]) {
continue;
}
[sqliteString appendFormat:@"%@ = ? ", key];
[values addObject:dictionary[key]];
}
IGUnLock(_sqlLock);
if (values.count > 0) {
if ([self isStringVaild:parameters.whereParameters]) {
[sqliteString appendFormat:@"where %@", parameters.whereParameters];
} else {
debugLog(@"sql语句当中,where后面的参数为nil");
[sqliteString deleteCharactersInRange:NSMakeRange(sqliteString.length-1, 1)];
}
__block BOOL isSuccess;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString withArgumentsInArray:values];
}];
if (!isSuccess) {
debugLog(@"-----更改数据------");
}
return isSuccess;
} else {
debugLog(@"要更新的数据不能仅仅含有主键");
return NO;
}
}
#pragma mark - 查询数据
- (NSArray *)queryFromTable:(NSString * _Nonnull)tableName model:(Class _Nonnull)modelClass whereParameters:(IGParameters *)parameters {
if (![self checkTableName:tableName]) return nil;
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"select * from %@", tableName];
if (parameters && [self isStringVaild:parameters.whereParameters]) {
[sqliteString appendFormat:@" where %@", parameters.whereParameters];
}
IGUnLock(_sqlLock);
__block NSMutableArray *array = [NSMutableArray array];
NSDictionary *properties = [self getPropertiesWithModel:modelClass];
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
FMResultSet *res = [db executeQuery:sqliteString];
while ([res next]) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *key in properties) {
NSString *type = properties[key];
// 根据数据类型从数据库当中获取数据
if ([type isEqualToString:ig_sql_text]) {
// 字符串
dict[key] = [res stringForColumn:key] ? : @"";
} else if ([type isEqualToString:ig_sql_integer]) {
// 整型
dict[key] = @([res longLongIntForColumn:key]);
} else if ([type isEqualToString:ig_sql_real]) {
// 浮点型
dict[key] = @([res doubleForColumn:key]);
} else if ([type isEqualToString:ig_sql_blob]) {
// 二进制
id value = [res dataForColumn:key];
if (value) {
dict[key] = value;
}
}
}
[array addObject:dict];
}
}];
return (array.count > 0 ? array : nil);
}
#pragma mark - 除去增删改查之外常用的功能
/**
* 表是否存在
* @param tableName 表的名字
* @return 表是否存在
*/
- (BOOL)existTable:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) return NO;
__block BOOL isExist;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
FMResultSet *res = [db executeQuery:@"select count(*) as 'count' from sqlite_master where type ='table' and name = ?", tableName];
while ([res next]) {
NSInteger count = [res intForColumn:@"count"];
isExist = ((count == 0) ? NO : YES);
}
}];
return isExist;
}
/**
* 为一个表增加字段
* @param tableName 表的名字
* @param column 要增加的字段
* @param type 增加的字段类型
* @return 是否添加成功
*/
- (BOOL)alterTable:(NSString * _Nonnull)tableName column:(NSString * _Nonnull)column type:(IGFMDBValueType)type {
if (![self checkTableName:tableName]) return NO;
if (![self isStringVaild:column]) {
debugLog(@"---要新增的column必须是字符串,且不能为nil-----");
return NO;
}
IGLock(_sqlLock);
NSString *typeString = nil;
switch (type) {
case IGFMDBValueTypeString:
typeString = ig_sql_text;
break;
case IGFMDBValueTypeInteger:
typeString = ig_sql_integer;
break;
case IGFMDBValueTypeFloat:
typeString = ig_sql_real;
break;
case IGFMDBValueTypeData:
typeString = ig_sql_blob;
break;
default:
typeString = @"";
break;
}
NSString *sqliteString = [NSString stringWithFormat:@"alter table %@ add column %@ %@", tableName, column, typeString];
IGUnLock(_sqlLock);
__block BOOL isSuccess;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString];
}];
return isSuccess;
}
/**
* 删除一张表
* @param tableName 表的名字
* @return 是否删除成功
*/
- (BOOL)dropTable:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) return NO;
IGLock(_sqlLock);
NSString *sqliteString = [NSString stringWithFormat:@"drop table %@", tableName];
IGUnLock(_sqlLock);
__block BOOL isSuccess ;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
isSuccess = [db executeUpdate:sqliteString];
}];
return isSuccess;
}
/**
* 获取某一个表中所有的字段名
* @param tableName 表的名字
* @return 所有字段名
*/
- (NSArray<NSString *> *)getAllColumnsFromTable:(NSString * _Nonnull)tableName {
if (![self checkTableName:tableName]) return nil;
return [self getAllColumnsFromTable:tableName dbQueue:self.dbQueue isIncludingPrimaryKey:YES];
}
/**
* 获取表中有多少条数据
* @param tableName 表的名字
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数
* @return 数据的个数
*/
- (long long int)numberOfItemsFromTable:(NSString * _Nonnull)tableName whereParameters:(IGParameters * _Nullable)parameters {
if (![self checkTableName:tableName]) return 0;
IGLock(_sqlLock);
NSMutableString *sqliteString = [NSMutableString stringWithFormat:@"select count(*) as 'count' from %@", tableName];
if (parameters && [self isStringVaild:parameters.whereParameters]) {
[sqliteString appendFormat:@" where %@", parameters.whereParameters];
}
IGUnLock(_sqlLock);
__block long long count ;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
FMResultSet *res = [db executeQuery:sqliteString];
while ([res next]) {
count = [res longLongIntForColumn:@"count"];
}
}];
return count;
}
/**
* 数学相关操作
* @param type 数学运算的type
* @param tableName 表的名字
* @param parameters 参数,IGParameters决定了sql语句"where"后面的参数
* @return 计算的值
*/
- (double)numberWithMathType:(IGFMDBMathType)type table:(NSString * _Nonnull)tableName column:(NSString * _Nonnull)column whereParameters:(IGParameters * _Nullable)parameters {
if (![self checkTableName:tableName]) return 0;
if (![self isStringVaild:parameters.whereParameters]) {
debugLog(@"---要新增的column必须是字符串,且不能为nil----");
return 0.0;
}
IGLock(_sqlLock);
NSMutableString *sqliteString = nil;
NSString *operation = nil;
switch (type) {
case IGFMDBMathTypeSum:
operation = @"sum";
break;
case IGFMDBMathTypeAvg:
operation = @"avg";
break;
case IGFMDBMathTypeMax:
operation = @"max";
break;
case IGFMDBMathTypeMin:
operation = @"min";
break;
default:
break;
}
if ([self isStringVaild:operation]) {
sqliteString = [NSMutableString stringWithFormat:@"select %@(%@) %@Count from %@", operation, column, operation, tableName];
} else {
debugLog(@"----不支持当前运算----");
}
if (parameters) {
[sqliteString appendFormat:@" where %@", parameters.whereParameters];
}
IGUnLock(_sqlLock);
__block double value = 0.0;
[_dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
FMResultSet *res = [db executeQuery:sqliteString];
while ([res next]) {
value = [res doubleForColumn:[NSString stringWithFormat:@"%@Count", operation]];
}
}];
return value;
}
#pragma mark - 数据库相关操作
// 获取数据库里的所有元素
- (NSArray<NSString *> *)getAllColumnsFromTable:(NSString *)tableName dbQueue:(FMDatabaseQueue *)dbQueue isIncludingPrimaryKey:(BOOL)isIncluding {
__block NSMutableArray *columns = [NSMutableArray array];
[dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
FMResultSet *res = [db getTableSchema:tableName];
while ([res next]) {
NSString *columnName = [res stringForColumn:@"name"];
if ([columnName isEqualToString:ig_primary_key] && !isIncluding) {
continue;
}
[columns addObject:columnName];
}
}];
return columns;
}
#pragma mark - Private Method
/**
* 基于runtime获取model的所有属性以及类型
* 根据传入的ModelClass去获取所有的属性的key以及类型type,返回值的字典的key就是modelClass的属性,value就是modelClass的属性对应的type
*/
- (NSDictionary *)getPropertiesWithModel:(Class)modelClass {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
unsigned int count;
objc_property_t *propertyList = class_copyPropertyList(modelClass, &count);
for (int index = 0; index < count; index++) {
objc_property_t property = propertyList[index];
NSString *key = [NSString stringWithFormat:@"%s", property_getName(property)];
NSString *type = nil;
NSString *attributes = [NSString stringWithFormat:@"%s", property_getAttributes(property)];
if ([attributes hasPrefix:@"T@\"NSString\""]) {
type = ig_sql_text;
} else if ([attributes hasPrefix:@"Tf"] || [attributes hasPrefix:@"Td"]) {
type = ig_sql_real;
} else if ([attributes hasPrefix:@"T@\"NSData\""]) {
type = ig_sql_blob;
} else if ([attributes hasPrefix:@"Ti"] || [attributes hasPrefix:@"TI"] || [attributes hasPrefix:@"Tl"] || [attributes hasPrefix:@"TL"] || [attributes hasPrefix:@"Tq"] || [attributes hasPrefix:@"TQ"] || [attributes hasPrefix:@"Ts"] || [attributes hasPrefix:@"TS"] || [attributes hasPrefix:@"TB"] || [attributes hasPrefix:@"T@\"NSNumber\""]) {
type = ig_sql_integer;
}
if (type) {
[dict setObject:type forKey:key];
} else {
debugLog(@"---%@----",[NSString stringWithFormat:@"不支持的属性:key = %@, attributes = %@", key, attributes]);
}
}
free(propertyList);
return dict;
}
// 根据keys获取到model里面的所有values
- (NSArray *)getValuesFromModel:(id _Nonnull)model columns:(NSArray *)columns {
NSMutableArray *array = [NSMutableArray array];
for (NSString *column in columns) {
id value = [model valueForKey:column];
[array addObject:value ? : @""];
}
return array;
}
// 加锁
void IGLock(dispatch_semaphore_t semaphore) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
// 解锁
void IGUnLock(dispatch_semaphore_t semaphore) {
dispatch_semaphore_signal(semaphore);
}
@end
IGParameters.h 文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
// 参数相关的关系
typedef NS_ENUM(NSUInteger, IGParametersRelationType) {
IGParametersRelationTypeEqualTo, // 数学运算@"=",等于
IGParametersRelationTypeUnequalTo, // 数学运算@"!=",不等于
IGParametersRelationTypeGreaterThan, // 数学运算@">",大于
IGParametersRelationTypeGreaterThanOrEqualTo, // 数学运算@">=",大于等于
IGParametersRelationTypeLessThan, // 数学运算@"<",小于
IGParametersRelationTypeLessThanOrEqualTo, // 数学运算@"<=",小于等于
IGParametersRelationTypeLike, // 字符串运算@"like",模糊查询 这个又有左右模糊之分
};
// 排序顺序
typedef NS_ENUM(NSUInteger, IGParametersOrderType) {
IGParametersOrderTypeAsc, // 升序
IGParametersOrderTypeDesc, // 降序
};
@interface IGParameters : NSObject
#pragma mark - sql语句当中为where之后的条件增加参数
/**
* 筛选条件的数量限制
*/
@property (nonatomic, assign) NSInteger limitCount;
/**
* and(&&,与)操作
* @param column 数据库中表的key值
* @param value column值对应的value值
* @param relationType column与value之间的关系
* 比如只执行[andWhere:@"age" value:18 relationType:IGParametersRelationTypeGreaterThan],那么where后面的参数会变成"age > 18"
*/
- (void)andWhere:(NSString * _Nonnull)column value:(id _Nonnull)value relationType:(IGParametersRelationType)relationType;
/**
* or(||,或)操作
* @param column 数据库中表的key值
* @param value column值对应的value值
* @param relationType column与value之间的关系
*/
- (void)orWhere:(NSString * _Nonnull)column value:(id _Nonnull)value relationType:(IGParametersRelationType)relationType;
/**
* 设置排序结果
* @param column 排序的字段
* @param orderType 排序选择,有升序和降序
* 比如执行[ orderByColumn:@"Id" orderType:IGParametersOrderTypeAsc],那么对应的sql语句就是@"order by Id asc",意思就是根据"Id"来进行升序排列
*/
- (void)orderByColumn:(NSString * _Nonnull)column orderType:(IGParametersOrderType)orderType;
/**
* sql语句的参数,也就是sql语句当中,where之后的参数.
* 值得一提的是,如果设置了这个参数,那么在属性whereParameters上面的方法都无效
* 如果不设置这个参数,那么调用此属性的get方法则会获取到以上的方法所形成的sql语句
*/
@property (nonatomic, copy) NSString *whereParameters;
@end
NS_ASSUME_NONNULL_END
IGParameters.m 文件
#import "IGParameters.h"
@interface IGParameters ()
@property (nonatomic, strong) NSMutableArray<NSString *> *andParameters; // and参数
@property (nonatomic, strong) NSMutableArray<NSString *> *orParameters; // or参数
@property (nonatomic, copy) NSString *orderString; // 排序语句
@end
@implementation IGParameters
- (NSMutableArray<NSString *> *)andParameters {
if (!_andParameters) {
_andParameters = [NSMutableArray array];
}
return _andParameters;
}
- (NSMutableArray<NSString *> *)orParameters {
if (!_orParameters) {
_orParameters = [NSMutableArray array];
}
return _orParameters;
}
- (NSString *)whereParameters {
if (_whereParameters) {
return _whereParameters;
} else {
NSMutableString *string = [NSMutableString string];
NSString *andString = [self.andParameters componentsJoinedByString:@" and "];
NSString *orString = [self.orParameters componentsJoinedByString:@" or "];
if (andString && andString.length > 0) {
[string appendFormat:@"%@", andString];
}
if (orString && orString.length > 0) {
[string appendFormat:@"%@%@", (string.length > 0 ? @" or " : @""), orString];
}
if (self.orderString) {
[string appendFormat:@" %@", self.orderString];
}
if (self.limitCount > 0) {
[string appendFormat:@" limit %ld", (long)self.limitCount];
}
return (NSString *)(string.length > 0 ? string : nil);
}
}
/**
* and(&&,与)操作
*/
- (void)andWhere:(NSString * _Nonnull)column value:(id _Nonnull)value relationType:(IGParametersRelationType)relationType {
if ([value isKindOfClass:[NSString class]] && relationType != IGParametersRelationTypeLike) {
value = [NSString stringWithFormat:@"'%@'",value]; //如果是字符串, 外面会加 单引号
}
NSString *string = nil;
switch (relationType) {
case IGParametersRelationTypeEqualTo:
string = [NSString stringWithFormat:@"%@ = %@", column, value];
break;
case IGParametersRelationTypeUnequalTo:
string = [NSString stringWithFormat:@"%@ != %@", column, value];
break;
case IGParametersRelationTypeGreaterThan:
string = [NSString stringWithFormat:@"%@ > %@", column, value];
break;
case IGParametersRelationTypeGreaterThanOrEqualTo:
string = [NSString stringWithFormat:@"%@ >= %@", column, value];
break;
case IGParametersRelationTypeLessThan:
string = [NSString stringWithFormat:@"%@ < %@", column, value];
break;
case IGParametersRelationTypeLessThanOrEqualTo:
string = [NSString stringWithFormat:@"%@ <= %@", column, value];
break;
case IGParametersRelationTypeLike:
{
//左右都要模糊 %%%@%%
//左模糊 %%%@
//右模糊 %@%%
string = [NSString stringWithFormat:@"%@ like '%@%%' ", column, value];
}
break;
default:
break;
}
if (string) {
[self.andParameters addObject:string];
}
}
/**
* or(||,或)操作
*/
- (void)orWhere:(NSString * _Nonnull)column value:(id _Nonnull)value relationType:(IGParametersRelationType)relationType {
NSString *string = nil;
switch (relationType) {
case IGParametersRelationTypeEqualTo:
string = [NSString stringWithFormat:@"%@ = %@", column, value];
break;
case IGParametersRelationTypeUnequalTo:
string = [NSString stringWithFormat:@"%@ != %@", column, value];
break;
case IGParametersRelationTypeGreaterThan:
string = [NSString stringWithFormat:@"%@ > %@", column, value];
break;
case IGParametersRelationTypeGreaterThanOrEqualTo:
string = [NSString stringWithFormat:@"%@ >= %@", column, value];
break;
case IGParametersRelationTypeLessThan:
string = [NSString stringWithFormat:@"%@ < %@", column, value];
break;
case IGParametersRelationTypeLessThanOrEqualTo:
string = [NSString stringWithFormat:@"%@ <= %@", column, value];
break;
default:
break;
}
if (string) {
[self.orParameters addObject:string];
}
}
/**
* 设置排序结果
*/
- (void)orderByColumn:(NSString * _Nonnull)column orderType:(IGParametersOrderType)orderType {
if (orderType == IGParametersOrderTypeAsc) {
self.orderString = [NSString stringWithFormat:@"order by %@ asc", column];
} else if (orderType == IGParametersOrderTypeDesc) {
self.orderString = [NSString stringWithFormat:@"order by %@ desc", column];
}
}
@end