From 1a3ff9710c329d574f6963996478edd8b2dc23c9 Mon Sep 17 00:00:00 2001 From: gychao Date: Fri, 19 Aug 2016 12:20:52 +0800 Subject: [PATCH] =?UTF-8?q?1=20=E8=87=AA=E5=AE=9A=E4=B9=89=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JKDBModel.xcodeproj/project.pbxproj | 6 + JKDBModel/DBModel/JKDBModel.h | 164 +++++++- JKDBModel/DBModel/JKDBModel.m | 605 +++++++++++++++++++++++----- JKDBModel/DBModel/ZXCommonTool.h | 48 +++ JKDBModel/DBModel/ZXCommonTool.m | 130 ++++++ 5 files changed, 831 insertions(+), 122 deletions(-) mode change 100644 => 100755 JKDBModel/DBModel/JKDBModel.h mode change 100644 => 100755 JKDBModel/DBModel/JKDBModel.m create mode 100644 JKDBModel/DBModel/ZXCommonTool.h create mode 100644 JKDBModel/DBModel/ZXCommonTool.m diff --git a/JKDBModel.xcodeproj/project.pbxproj b/JKDBModel.xcodeproj/project.pbxproj index 0ca81a3..63a5956 100644 --- a/JKDBModel.xcodeproj/project.pbxproj +++ b/JKDBModel.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0DA45A381D66C0630092E1DE /* ZXCommonTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA45A371D66C0630092E1DE /* ZXCommonTool.m */; }; 610FA0101B43D36F00CA50C6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 610FA00F1B43D36F00CA50C6 /* main.m */; }; 610FA0131B43D36F00CA50C6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 610FA0121B43D36F00CA50C6 /* AppDelegate.m */; }; 610FA01B1B43D36F00CA50C6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 610FA01A1B43D36F00CA50C6 /* Images.xcassets */; }; @@ -38,6 +39,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0DA45A361D66C0630092E1DE /* ZXCommonTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCommonTool.h; sourceTree = ""; }; + 0DA45A371D66C0630092E1DE /* ZXCommonTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCommonTool.m; sourceTree = ""; }; 610FA00A1B43D36F00CA50C6 /* JKDBModel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JKDBModel.app; sourceTree = BUILT_PRODUCTS_DIR; }; 610FA00E1B43D36F00CA50C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 610FA00F1B43D36F00CA50C6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -185,6 +188,8 @@ 610FA0421B43D44300CA50C6 /* JKDBHelper.m */, 610FA0431B43D44300CA50C6 /* JKDBModel.h */, 610FA0441B43D44300CA50C6 /* JKDBModel.m */, + 0DA45A361D66C0630092E1DE /* ZXCommonTool.h */, + 0DA45A371D66C0630092E1DE /* ZXCommonTool.m */, ); path = DBModel; sourceTree = ""; @@ -313,6 +318,7 @@ 610FA03F1B43D43B00CA50C6 /* User.m in Sources */, 6157C3A51B5B3A1800592F3F /* QueryTableViewController.m in Sources */, 610FA0561B43D44A00CA50C6 /* FMDatabaseQueue.m in Sources */, + 0DA45A381D66C0630092E1DE /* ZXCommonTool.m in Sources */, 610FA0571B43D44A00CA50C6 /* FMResultSet.m in Sources */, 610FA0551B43D44A00CA50C6 /* FMDatabasePool.m in Sources */, 610FA0381B43D42E00CA50C6 /* ViewController.m in Sources */, diff --git a/JKDBModel/DBModel/JKDBModel.h b/JKDBModel/DBModel/JKDBModel.h old mode 100644 new mode 100755 index 8194059..b4875fe --- a/JKDBModel/DBModel/JKDBModel.h +++ b/JKDBModel/DBModel/JKDBModel.h @@ -8,6 +8,8 @@ #import + + /** SQLite五种数据类型 */ #define SQLTEXT @"TEXT" #define SQLINTEGER @"INTEGER" @@ -18,21 +20,51 @@ #define primaryId @"pk" + + +/** + * + * + * 数据 model 继承自 JKDBModel + * 在这里 直接维护 数据库的操作 + * + * note: armv6 v7 时候的 几种基本类型 对应数据库 字段类型 + * 大部分情况下,我们并不需要 主键. + * + * tips: + 1.主键 pk ,查找什么的完全依赖主键pk,这是一个大问题。这里对是否需要创建pk 自定义 ,默认不需要 + * 2.根据 conditionArray 指定的 列名称,进行条件判断 + * 3.列名称为空的 不会建表 + * + * 更多的 自定义功能,可以直接 本类进行修改 + * + * https://github.com/Haley-Wong/JKDBModel + */ + + @interface JKDBModel : NSObject +// 这个主键 没有什么实际作用 +// 起主键名字 是很困难的, /** 主键 id */ @property (nonatomic, assign) int pk; -/** 列名 */ + +/** 列名 */ @property (retain, readonly, nonatomic) NSMutableArray *columeNames; /** 列类型 */ @property (retain, readonly, nonatomic) NSMutableArray *columeTypes; +/** + * 从数据库返回的model YES + */ +@property (nonatomic,assign)BOOL comefromDB; + /** * 获取该类的所有属性 */ + (NSDictionary *)getPropertys; -/** 获取所有属性,包括主键 */ +/** 获取所有属性,包括主键 ,如果不需要主键,则不包含*/ + (NSDictionary *)getAllProperties; /** 数据库中是否存在表 */ @@ -41,32 +73,144 @@ /** 表中的字段*/ + (NSArray *)getColumns; + +/** + * 创建表 + * 如果已经创建,返回YES + */ ++ (BOOL)createTable; + + +#pragma mark - override + +/**< 需要被overrite 的方法 + + require + update delete select 的判断依据字段 + */ ++ (NSArray *)conditionArray; + +/**< 保存的时候 执行 update的 不能|不需要 进行修改的 列名字 + 如果overide 了这个api ,后续需要更新这些字断 可以使用 + + zx_updateNoNeedInSaveOrUpdateArray || + zx_updateWithSql + + option + + */ ++ (NSArray *)noNeedInSaveOrUpdateArray; + + +/** 如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写 + + option + */ ++ (NSArray *)transients; + +/** + * 是否需要主键 + * 默认不需要 + * @return YES 需要 No 不需要 + */ ++ (BOOL)needPk; + + +#pragma mark - for Common +#pragma mark - 以下api 是 依赖 conditionArray 条件的列字段 + +/** 通过依赖关系 批量保存 或者 更新 数据 */ ++ (BOOL)zx_saveOrUpdateObjects:(NSArray *)array; + +/** + * 单个 插入 + * @return YES 成功,NO 失败 + */ +- (BOOL)zx_insert; + + +/** + * 单个更新 + */ +- (BOOL)zx_updateNoNeedInSaveOrUpdateArray; + +/** + * 子类可以 override 这些 来更新 特定列名 + * 单独更新 + * + * @param sql + */ +- (BOOL)zx_updateWithSql:(NSString *)sql; + + +#pragma mark - 查找 从数据库中 + +/** + * 从数据库找到所有的 model + * + * @return + */ ++ (NSArray *)zx_findAll; + +/** + * 根据model 和 依赖关系 直接查找 + * + * @return 返回 找到返回model ,没有 返回nil + */ +- (instancetype )zx_find; + + + + + + +#pragma mark - DEPRECATED +#pragma mark - 以下api 是依赖主键pk的 + + /** 保存或更新 * 如果不存在主键,保存, * 有主键,则更新 */ - (BOOL)saveOrUpdate; + + +/** 批量保存数据 */ ++ (BOOL)saveObjects:(NSArray *)array; + + + /** 保存或更新 * 如果根据特定的列数据可以获取记录,则更新, * 没有记录,则保存 */ - (BOOL)saveOrUpdateByColumnName:(NSString*)columnName AndColumnValue:(NSString*)columnValue; + + /** 保存单个数据 */ - (BOOL)save; -/** 批量保存数据 */ -+ (BOOL)saveObjects:(NSArray *)array; + + /** 更新单个数据 */ - (BOOL)update; + /** 批量更新数据*/ + (BOOL)updateObjects:(NSArray *)array; + + /** 删除单个数据 */ - (BOOL)deleteObject; + + /** 批量删除数据 */ + (BOOL)deleteObjects:(NSArray *)array; + /** 通过条件删除数据 */ + (BOOL)deleteObjectsByCriteria:(NSString *)criteria; + /** 通过条件删除 (多参数)--2 */ + (BOOL)deleteObjectsWithFormat:(NSString *)format, ...; + /** 清空表 */ + (BOOL)clearTable; @@ -87,16 +231,10 @@ * 这样可以进行分页查询 @" WHERE pk > 5 limit 10" */ + (NSArray *)findByCriteria:(NSString *)criteria; -/** - * 创建表 - * 如果已经创建,返回YES - */ -+ (BOOL)createTable; -#pragma mark - must be override method -/** 如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写 - */ -+ (NSArray *)transients; + + +#pragma mark - for custom @end diff --git a/JKDBModel/DBModel/JKDBModel.m b/JKDBModel/DBModel/JKDBModel.m old mode 100644 new mode 100755 index 9a093d1..0659fe6 --- a/JKDBModel/DBModel/JKDBModel.m +++ b/JKDBModel/DBModel/JKDBModel.m @@ -7,10 +7,23 @@ // github:https://github.com/Joker-King/JKDBModel #import "JKDBModel.h" + #import "JKDBHelper.h" +#import "ZXCommonTool.h" #import +@interface JKDBModel () + +// 获取这个属性值的详细类型 +// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101 + +@property (nonatomic,strong)NSMutableArray * columnDetailTypes; + +@end + + + @implementation JKDBModel #pragma mark - override method @@ -28,6 +41,7 @@ - (instancetype)init NSDictionary *dic = [self.class getAllProperties]; _columeNames = [[NSMutableArray alloc] initWithArray:[dic objectForKey:@"name"]]; _columeTypes = [[NSMutableArray alloc] initWithArray:[dic objectForKey:@"type"]]; + _columnDetailTypes = [[NSMutableArray alloc] initWithArray:[dic objectForKey:@"detailType"]]; } return self; @@ -41,6 +55,8 @@ + (NSDictionary *)getPropertys { NSMutableArray *proNames = [NSMutableArray array]; NSMutableArray *proTypes = [NSMutableArray array]; + NSMutableArray *detailProTypes = [NSMutableArray array]; + NSArray *theTransients = [[self class] transients]; unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList([self class], &outCount); @@ -54,6 +70,7 @@ + (NSDictionary *)getPropertys [proNames addObject:propertyName]; //获取属性类型等参数 NSString *propertyType = [NSString stringWithCString: property_getAttributes(property) encoding:NSUTF8StringEncoding]; + [detailProTypes addObject:propertyType]; /* 各种符号对应类型,部分类型在新版SDK中有所变化,如long 和long long c char C unsigned char @@ -82,7 +99,7 @@ + (NSDictionary *)getPropertys } free(properties); - return [NSDictionary dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",nil]; + return [NSDictionary dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",detailProTypes,@"detailType",nil]; } /** 获取所有属性,包含主键pk */ @@ -92,12 +109,19 @@ + (NSDictionary *)getAllProperties NSMutableArray *proNames = [NSMutableArray array]; NSMutableArray *proTypes = [NSMutableArray array]; - [proNames addObject:primaryId]; - [proTypes addObject:[NSString stringWithFormat:@"%@ %@",SQLINTEGER,PrimaryKey]]; + NSMutableArray * detailTypes = [NSMutableArray array]; + + if ([self needPk]) { + //这里添加了主键 + [proNames addObject:primaryId]; + [proTypes addObject:[NSString stringWithFormat:@"%@ %@",SQLINTEGER,PrimaryKey]]; + } + [proNames addObjectsFromArray:[dict objectForKey:@"name"]]; [proTypes addObjectsFromArray:[dict objectForKey:@"type"]]; + [detailTypes addObjectsFromArray:[dict objectForKey:@"detailType"]]; - return [NSDictionary dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",nil]; + return [NSDictionary dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",detailTypes,@"detailType",nil]; } /** 数据库中是否存在表 */ @@ -124,6 +148,7 @@ + (NSArray *)getColumns NSString *column = [resultSet stringForColumn:@"name"]; [columns addObject:column]; } + [resultSet close]; }]; return [columns copy]; } @@ -140,6 +165,9 @@ + (BOOL)createTable NSString *tableName = NSStringFromClass(self.class); NSString *columeAndType = [self.class getColumeAndTypeString]; NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@);",tableName,columeAndType]; + + NSLog(@"建立表sql %@",sql); + if (![db executeUpdate:sql]) { res = NO; *rollback = YES; @@ -147,11 +175,14 @@ + (BOOL)createTable }; NSMutableArray *columns = [NSMutableArray array]; + FMResultSet *resultSet = [db getTableSchema:tableName]; while ([resultSet next]) { NSString *column = [resultSet stringForColumn:@"name"]; [columns addObject:column]; } + [resultSet close]; + NSDictionary *dict = [self.class getAllProperties]; NSArray *properties = [dict objectForKey:@"name"]; NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)",columns]; @@ -162,6 +193,7 @@ + (BOOL)createTable NSString *proType = [[dict objectForKey:@"type"] objectAtIndex:index]; NSString *fieldSql = [NSString stringWithFormat:@"%@ %@",column,proType]; NSString *sql = [NSString stringWithFormat:@"ALTER TABLE %@ ADD COLUMN %@ ",NSStringFromClass(self.class),fieldSql]; + NSLog(@"更新表sql %@",sql); if (![db executeUpdate:sql]) { res = NO; *rollback = YES; @@ -173,82 +205,286 @@ + (BOOL)createTable return res; } + + + +#pragma mark - util method ++ (NSString *)getColumeAndTypeString +{ + NSMutableString* pars = [NSMutableString string]; + NSDictionary *dict = [self.class getAllProperties]; + + NSMutableArray *proNames = [dict objectForKey:@"name"]; + NSMutableArray *proTypes = [dict objectForKey:@"type"]; + + for (int i=0; i< proNames.count; i++) { + [pars appendFormat:@"%@ %@",[proNames objectAtIndex:i],[proTypes objectAtIndex:i]]; + if(i+1 != proNames.count) + { + [pars appendString:@","]; + } + } + return pars; +} + +- (NSString *)description +{ + NSString *result = @""; + NSDictionary *dict = [self.class getAllProperties]; + NSMutableArray *proNames = [dict objectForKey:@"name"]; + for (int i = 0; i < proNames.count; i++) { + NSString *proName = [proNames objectAtIndex:i]; + id proValue = [self valueForKey:proName]; + result = [result stringByAppendingFormat:@"%@:%@\n",proName,proValue]; + } + return result; +} + +#pragma mark - must be override method +/** 如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写 + */ ++ (NSArray *)transients +{ + return [NSArray array]; +} + + ++ (NSArray *)conditionArray{ + + return @[]; +} + ++ (NSArray *)noNeedInSaveOrUpdateArray{ + return @[]; +} + /** - * 创建表 - * 如果已经创建,返回YES + * 是否需要主键 + * 默认不需要 + * @return YES 需要 No 不需要 */ -//+ (BOOL)createTable -//{ -// FMDatabase *db = [FMDatabase databaseWithPath:[JKDBHelper dbPath]]; -// if (![db open]) { -// NSLog(@"数据库打开失败!"); -// return NO; -// } -// -// NSString *tableName = NSStringFromClass(self.class); -// NSString *columeAndType = [self.class getColumeAndTypeString]; -// NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@);",tableName,columeAndType]; -// if (![db executeUpdate:sql]) { -// return NO; -// } -// -// NSMutableArray *columns = [NSMutableArray array]; -// FMResultSet *resultSet = [db getTableSchema:tableName]; -// while ([resultSet next]) { -// NSString *column = [resultSet stringForColumn:@"name"]; -// [columns addObject:column]; -// } -// NSDictionary *dict = [self.class getAllProperties]; -// NSArray *properties = [dict objectForKey:@"name"]; -// NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)",columns]; -// //过滤数组 -// NSArray *resultArray = [properties filteredArrayUsingPredicate:filterPredicate]; -// -// for (NSString *column in resultArray) { -// NSUInteger index = [properties indexOfObject:column]; -// NSString *proType = [[dict objectForKey:@"type"] objectAtIndex:index]; -// NSString *fieldSql = [NSString stringWithFormat:@"%@ %@",column,proType]; -// NSString *sql = [NSString stringWithFormat:@"ALTER TABLE %@ ADD COLUMN %@ ",NSStringFromClass(self.class),fieldSql]; -// if (![db executeUpdate:sql]) { -// return NO; -// } -// } -// [db close]; -// return YES; -//} ++ (BOOL)needPk{ + return NO; +} -- (BOOL)saveOrUpdate -{ - id primaryValue = [self valueForKey:primaryId]; - if ([primaryValue intValue] <= 0) { - return [self save]; + +/** + * valueForKey + * 保存数据库的使用 array dictionary 转成 json string + * @return + */ +- (id)zx_valueForKey:(NSString *)key{ + id value = [self valueForKey:key]; + if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) { + value = [NSJSONSerialization dataWithJSONObject:value options:NSJSONWritingPrettyPrinted error:nil]; } + return value; +} + + +#pragma mark - 以下 api 是 依赖 conditionArray 列名称的 + +/** + * 根据条件 从数据库中查找 + * + */ ++ (NSArray *)zx_findByCriteria:(NSString *)criteria inDB:(FMDatabase *)db{ - return [self update]; + NSMutableArray * users = [NSMutableArray array]; + + NSString *tableName = NSStringFromClass(self.class); + NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@ %@",tableName,criteria]; + FMResultSet *resultSet = [db executeQuery:sql]; + while ([resultSet next]) { + JKDBModel *model = [self fetchResult:resultSet]; + [users addObject:model]; + } + [resultSet close]; + + return users; } -- (BOOL)saveOrUpdateByColumnName:(NSString*)columnName AndColumnValue:(NSString*)columnValue -{ - id record = [self.class findFirstByCriteria:[NSString stringWithFormat:@"where %@ = %@",columnName,columnValue]]; - if (record) { - id primaryValue = [record valueForKey:primaryId]; //取到了主键PK - if ([primaryValue intValue] <= 0) { - return [self save]; - }else{ - self.pk = [primaryValue integerValue]; - return [self update]; +#pragma mark - 解析从数据库 得到的结果 ++ (JKDBModel *)fetchResult:(FMResultSet *)resultSet{ + + JKDBModel *model = [[self.class alloc] init]; + for (int i=0; i< model.columeNames.count; i++) { + NSString *columeName = [model.columeNames objectAtIndex:i]; + NSString *columeType = [model.columeTypes objectAtIndex:i]; + NSString *detailType =[model.columnDetailTypes objectAtIndex:i]; + + //TODO 注意这里的转换 + if ([columeType isEqualToString:SQLTEXT]) { + + NSString * result = [resultSet stringForColumn:columeName]; + id obj; + if ([detailType hasPrefix:@"T@\"NSMutableArray\""]||[detailType hasPrefix:@"T@\"NSArray\""]) { + // 数组 + obj = [NSJSONSerialization JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil]; + } + else if([detailType hasPrefix:@"T@\"NSMutableDictionary\""]||[detailType hasPrefix:@"T@\"NSDictionary\""]){ + // 字典 + obj = [NSJSONSerialization JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil]; + }else{ + obj = result; + } + + [model setValue:obj forKey:columeName]; + + } else { + [model setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columeName]] forKey:columeName]; } - }else{ - return [self save]; } + return model; } -- (BOOL)save -{ + +/** + * 根据model 从数据库中查找 是否包含model 指定条件的 数据 + * + */ ++ (NSArray *)zx_findFromTableByModel:(JKDBModel *)dbModel inDB:(FMDatabase *)db{ + + if ([ZXCommonTool zx_arrayIsEmpty:[self conditionArray]]) { + return @[]; + } + NSString * sql = [self zx_findWhereSqlByModel:dbModel]; + + return [self zx_findByCriteria:sql inDB:db]; +} + +/** + * 根据model 指定条件数组 生成查找 where 语句 + * + */ ++ (NSString *)zx_findWhereSqlByModel:(JKDBModel *)dbModel{ + + if ([ZXCommonTool zx_arrayIsEmpty:[self conditionArray]]) { + return @""; + } + NSArray * conditionary = [[self class] conditionArray]; + NSMutableString * sql = [NSMutableString stringWithString:@"WHERE"]; + NSString * columnValue; + for (NSString * columnName in conditionary) { + columnValue = [dbModel zx_valueForKey:columnName]; + [sql appendFormat:@" %@=%@ and",columnName,columnValue]; + } + // 删除结尾的 " and" + [sql deleteCharactersInRange:NSMakeRange(sql.length - 4, 4)]; + return sql; +} + + +/** + * 批量插入 或 更新 依据依赖关系 + * + */ ++ (BOOL)zx_saveOrUpdateObjects:(NSArray *)array{ + if ([ZXCommonTool zx_arrayIsEmpty:array]) { + return NO; + } + + //判断是否是JKBaseModel的子类 如果存在非 JKBaseModel 子类 就有问题了 + for (JKDBModel *model in array) { + if (![model isKindOfClass:[JKDBModel class]]) { + return NO; + } + } + + __block BOOL res = YES; + JKDBHelper *jkDB = [JKDBHelper shareInstance]; + // 如果要支持事务 + [jkDB.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { + + NSArray * noNeedArray = [[self class] noNeedInSaveOrUpdateArray]; + + for (JKDBModel *model in array) { + + NSString *tableName = NSStringFromClass(model.class); + + NSMutableString *keyString = [NSMutableString string]; + NSMutableString *valueString = [NSMutableString string]; + NSMutableArray *insertValues = [NSMutableArray array]; + + NSString *sql; + BOOL flag; + // 判断是否存在 如果存在 则是更新 + NSArray * results = [self zx_findFromTableByModel:model inDB:db]; + + if ([ZXCommonTool zx_arrayIsEmpty:results]) { + //insert + for (int i = 0; i < model.columeNames.count; i++) { + NSString *proname = [model.columeNames objectAtIndex:i]; + if ([proname isEqualToString:primaryId]) { + continue; + } + [keyString appendFormat:@"%@,", proname]; + [valueString appendString:@"?,"]; + id value = [model zx_valueForKey:proname]; + if (!value) { + value = @""; + } + [insertValues addObject:value]; + + } + + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)]; + sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString]; + NSLog(@"插入的sql %@",sql); + flag = [db executeUpdate:sql withArgumentsInArray:insertValues]; + }else{ + //update + for (int i = 0; i < model.columeNames.count; i++) { + NSString *proname = [model.columeNames objectAtIndex:i]; + if ([proname isEqualToString:primaryId]) { + continue; + } + if ([noNeedArray containsObject:proname]) { + continue; + } + + id value = [model zx_valueForKey:proname]; + if (!value) { + value = @""; + } + [insertValues addObject:value]; + [keyString appendFormat:@"%@ = ?,", proname]; + } + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + valueString = [self zx_findWhereSqlByModel:model]; + + sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ %@", tableName, keyString, valueString]; + NSLog(@"更新的sql %@",sql); + flag = [db executeUpdate:sql withArgumentsInArray:insertValues]; + } + + model.pk = flag?[NSNumber numberWithLongLong:db.lastInsertRowId].intValue:0; + NSLog(flag?@"插入|更新 成功":@"插入|更新 失败"); + if (!flag) { + res = NO; + *rollback = YES; + return; + } + } + }]; + + return res; +} + + +/** + * 单个 插入 + * @return YES 成功,NO 失败 + */ +- (BOOL)zx_insert{ + NSString *tableName = NSStringFromClass(self.class); NSMutableString *keyString = [NSMutableString string]; NSMutableString *valueString = [NSMutableString string]; NSMutableArray *insertValues = [NSMutableArray array]; + NSString * sql; + //insert for (int i = 0; i < self.columeNames.count; i++) { NSString *proname = [self.columeNames objectAtIndex:i]; if ([proname isEqualToString:primaryId]) { @@ -256,7 +492,7 @@ - (BOOL)save } [keyString appendFormat:@"%@,", proname]; [valueString appendString:@"?,"]; - id value = [self valueForKey:proname]; + id value = [self zx_valueForKey:proname]; if (!value) { value = @""; } @@ -265,18 +501,136 @@ - (BOOL)save [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)]; + sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString]; + NSLog(@"插入的sql %@",sql); JKDBHelper *jkDB = [JKDBHelper shareInstance]; __block BOOL res = NO; - [jkDB.dbQueue inDatabase:^(FMDatabase *db) { - NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString]; + [jkDB.dbQueue inDatabase:^(FMDatabase *db){ res = [db executeUpdate:sql withArgumentsInArray:insertValues]; - self.pk = res?[NSNumber numberWithLongLong:db.lastInsertRowId].intValue:0; - NSLog(res?@"插入成功":@"插入失败"); + NSLog(res?@"单个插入成功":@"单个插入失败"); + }]; + return res; +} + + +#pragma mark - 更新 自定义列名 + +/** + * 单个更新 NoNeedInSaveOrUpdateArray + * + * @return + */ +- (BOOL)zx_updateNoNeedInSaveOrUpdateArray{ + + JKDBHelper *jkDB = [JKDBHelper shareInstance]; + __block BOOL res = NO; + [jkDB.dbQueue inDatabase:^(FMDatabase *db) { + + NSArray * noNeedArray = [[self class] noNeedInSaveOrUpdateArray]; + NSString *tableName = NSStringFromClass(self.class); + + NSMutableString *keyString = [NSMutableString string]; //update + NSMutableString *valueString = [NSMutableString string];//where + NSMutableArray *updateValues = [NSMutableArray array]; + NSString *sql; + + //update + for (int i = 0; i < noNeedArray.count; i++) { + NSString *proname = noNeedArray[i]; + if ([proname isEqualToString:primaryId]) { + continue; + } + id value = [self zx_valueForKey:proname]; + if (!value) { + value = @""; + } + [updateValues addObject:value]; + [keyString appendFormat:@"%@ = ?,", proname]; + } + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + valueString = [self.class zx_findWhereSqlByModel:self]; + + sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ %@", tableName, keyString, valueString]; + NSLog(@"更新noneed的sql %@",sql); + res = [db executeUpdate:sql withArgumentsInArray:updateValues]; + if (res) { + NSLog(@"更新noneed成功"); + } + }]; + return res; +} + +/** + * 子类可以 override 这些 来更新 特定列名 + * 单独更新 + * + * @param sql + */ +- (BOOL)zx_updateWithSql:(NSString *)sql{ + + JKDBHelper *jkDB = [JKDBHelper shareInstance]; + __block BOOL res = NO; + [jkDB.dbQueue inDatabase:^(FMDatabase *db) { + NSLog(@"单个自定义更新的sql %@",sql); + res = [db executeUpdate:sql]; + if (res) { + NSLog(@"单个自定义更新成功"); + }else{ + NSLog(@"单个自定义更新失败"); + } }]; return res; } + +#pragma mark - 查找 从数据库中 + ++ (NSArray *)zx_findAll{ + + NSLog(@"jkdb---%s",__func__); + JKDBHelper *jkDB = [JKDBHelper shareInstance]; + NSMutableArray *users = [NSMutableArray array]; + [jkDB.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = NSStringFromClass(self.class); + NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@",tableName]; + FMResultSet *resultSet = [db executeQuery:sql]; + while ([resultSet next]) { + + JKDBModel *model = [self fetchResult:resultSet]; + model.comefromDB = YES; + [users addObject:model]; + } + [resultSet close]; + + }]; + return users; +} + + +- (instancetype )zx_find{ + + JKDBHelper *jkDB = [JKDBHelper shareInstance]; + __block JKDBModel * model = nil; + [jkDB.dbQueue inDatabase:^(FMDatabase *db) { + + NSArray * result = [self.class zx_findFromTableByModel:self inDB:db]; + if (result.count) { + model = result[0]; + model.comefromDB = YES; + }else{ + + } + + }]; + return model; +} + + + +#pragma mark - DEPRECATED custom +#pragma mark - 以下是 通过主键 来判断区分的 + /** 批量保存用户对象 */ + (BOOL)saveObjects:(NSArray *)array { @@ -286,16 +640,17 @@ + (BOOL)saveObjects:(NSArray *)array return NO; } } - __block BOOL res = YES; JKDBHelper *jkDB = [JKDBHelper shareInstance]; // 如果要支持事务 [jkDB.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { + for (JKDBModel *model in array) { NSString *tableName = NSStringFromClass(model.class); NSMutableString *keyString = [NSMutableString string]; NSMutableString *valueString = [NSMutableString string]; NSMutableArray *insertValues = [NSMutableArray array]; + for (int i = 0; i < model.columeNames.count; i++) { NSString *proname = [model.columeNames objectAtIndex:i]; if ([proname isEqualToString:primaryId]) { @@ -326,6 +681,72 @@ + (BOOL)saveObjects:(NSArray *)array return res; } + +- (BOOL)save +{ + NSString *tableName = NSStringFromClass(self.class); + NSMutableString *keyString = [NSMutableString string]; + NSMutableString *valueString = [NSMutableString string]; + NSMutableArray *insertValues = [NSMutableArray array]; + for (int i = 0; i < self.columeNames.count; i++) { + NSString *proname = [self.columeNames objectAtIndex:i]; + if ([proname isEqualToString:primaryId]) { + continue; + } + [keyString appendFormat:@"%@,", proname]; + [valueString appendString:@"?,"]; + id value = [self valueForKey:proname]; + if (!value) { + value = @""; + } + [insertValues addObject:value]; + } + + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)]; + + JKDBHelper *jkDB = [JKDBHelper shareInstance]; + __block BOOL res = NO; + [jkDB.dbQueue inDatabase:^(FMDatabase *db) { + NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString]; + res = [db executeUpdate:sql withArgumentsInArray:insertValues]; + self.pk = res?[NSNumber numberWithLongLong:db.lastInsertRowId].intValue:0; + NSLog(res?@"插入成功":@"插入失败"); + }]; + return res; +} + + + + +- (BOOL)saveOrUpdate +{ + id primaryValue = [self valueForKey:primaryId]; + if ([primaryValue intValue] <= 0) { + return [self save]; + } + return [self update]; +} + +- (BOOL)saveOrUpdateByColumnName:(NSString*)columnName AndColumnValue:(NSString*)columnValue +{ + id record = [self.class findFirstByCriteria:[NSString stringWithFormat:@"where %@ = %@",columnName,columnValue]]; + if (record) { + id primaryValue = [record valueForKey:primaryId]; //取到了主键PK + if ([primaryValue intValue] <= 0) { + return [self save]; + }else{ + self.pk = [primaryValue integerValue]; + return [self update]; + } + }else{ + return [self save]; + } +} + + + + /** 更新单个对象 */ - (BOOL)update { @@ -415,6 +836,8 @@ + (BOOL)updateObjects:(NSArray *)array return res; } + + /** 删除单个对象 */ - (BOOL)deleteObject { @@ -529,6 +952,7 @@ + (NSArray *)findAll [users addObject:model]; FMDBRelease(model); } + [resultSet close]; }]; return users; @@ -594,49 +1018,12 @@ + (NSArray *)findByCriteria:(NSString *)criteria [users addObject:model]; FMDBRelease(model); } + [resultSet close]; }]; return users; } -#pragma mark - util method -+ (NSString *)getColumeAndTypeString -{ - NSMutableString* pars = [NSMutableString string]; - NSDictionary *dict = [self.class getAllProperties]; - - NSMutableArray *proNames = [dict objectForKey:@"name"]; - NSMutableArray *proTypes = [dict objectForKey:@"type"]; - - for (int i=0; i< proNames.count; i++) { - [pars appendFormat:@"%@ %@",[proNames objectAtIndex:i],[proTypes objectAtIndex:i]]; - if(i+1 != proNames.count) - { - [pars appendString:@","]; - } - } - return pars; -} - -- (NSString *)description -{ - NSString *result = @""; - NSDictionary *dict = [self.class getAllProperties]; - NSMutableArray *proNames = [dict objectForKey:@"name"]; - for (int i = 0; i < proNames.count; i++) { - NSString *proName = [proNames objectAtIndex:i]; - id proValue = [self valueForKey:proName]; - result = [result stringByAppendingFormat:@"%@:%@\n",proName,proValue]; - } - return result; -} -#pragma mark - must be override method -/** 如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写 - */ -+ (NSArray *)transients -{ - return [NSArray array]; -} @end diff --git a/JKDBModel/DBModel/ZXCommonTool.h b/JKDBModel/DBModel/ZXCommonTool.h new file mode 100644 index 0000000..f8b6723 --- /dev/null +++ b/JKDBModel/DBModel/ZXCommonTool.h @@ -0,0 +1,48 @@ +// +// ZXCommonTool.h +// yuyou +// +// Created by ganyanchao on 7/27/16. +// Copyright © 2016 Zhang Xiu Inc. All rights reserved. +// + +#import + +@interface ZXCommonTool : NSObject + + ++ (BOOL)zx_strIsEmpty:(NSString *)str; + ++ (BOOL)zx_arrayIsEmpty:(NSArray *)array; + ++ (BOOL)zx_dicIsEmpty:(NSDictionary *)dic; + + ++ (NSString *)replayPlaybackTimeFormatterWith:(long long)seconds; + +/** + * 安全取 str + * + * @param str 传入的str + * + * @return str 本身 或者 @"" + */ ++ (NSString *)safeOfString:(NSString *)str; + + +/** + * 设备型号 + * + * @return + */ ++(NSString *)deviceModel; + + +/** + * 设备code + * + * @return iphone5,5 + */ ++(NSString *)deviceCode; + +@end diff --git a/JKDBModel/DBModel/ZXCommonTool.m b/JKDBModel/DBModel/ZXCommonTool.m new file mode 100644 index 0000000..83528bb --- /dev/null +++ b/JKDBModel/DBModel/ZXCommonTool.m @@ -0,0 +1,130 @@ +// +// ZXCommonTool.m +// yuyou +// +// Created by ganyanchao on 7/27/16. +// Copyright © 2016 Zhang Xiu Inc. All rights reserved. +// + +#import "ZXCommonTool.h" +#import "sys/utsname.h" + + +@implementation ZXCommonTool + ++ (BOOL)zx_strIsEmpty:(NSString *)str{ + + return !(str && [str isKindOfClass:[NSString class]] && str.length &&![str isEqual:[NSNull null]]); +} + ++ (BOOL)zx_arrayIsEmpty:(NSArray *)array{ + + return !(array && [array isKindOfClass:[NSArray class]] && array.count && ![array isEqual:[NSNull null]]); +} + + ++ (BOOL)zx_dicIsEmpty:(NSDictionary *)dic{ + + return !(dic && [dic isKindOfClass:[NSDictionary class]] && dic.count && ![dic isEqual:[NSNull null]]); +} + ++ (NSString *)replayPlaybackTimeFormatterWith:(long long)msseconds{ + + long long seconds = ceil(msseconds / 1000); // ms - s + + long min = seconds / 60; + long sec = seconds % 60; + NSString * result = [NSString stringWithFormat:@"%ld:%02ld",min,sec]; + return result; +} + + ++ (NSString *)safeOfString:(NSString *)str{ + + if ([self zx_strIsEmpty:str]) { + return @""; + } + return str; +} + + + ++(NSString *)deviceModel{ + + struct utsname systemInfo; + uname(&systemInfo); + NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + + static NSDictionary * mapping; + if (!mapping) { + mapping = @{ + //iPhone + @"iPhone1,1":@"iPhone 1G", + @"iPhone1,2":@"iPhone 3G", + @"iPhone2,1":@"iPhone 3GS", + @"iPhone3,1":@"iPhone 4", + @"iPhone3,2":@"Verizon iPhone 4", + @"iPhone4,1":@"iPhone 4S", + @"iPhone5,1":@"iPhone 5", + @"iPhone5,2":@"iPhone 5", + @"iPhone5,3":@"iPhone 5C", + @"iPhone5,4":@"iPhone 5C", + @"iPhone6,1":@"iPhone 5S", + @"iPhone6,2":@"iPhone 5S", + @"iPhone7,1":@"iPhone 6 Plus", + @"iPhone7,2":@"iPhone 6", + @"iPhone8,1":@"iPhone 6s", + @"iPhone8,2":@"iPhone 6s Plus", + //iPod + @"iPod1,1":@"iPod Touch 1G", + @"iPod2,1":@"iPod Touch 2G", + @"iPod3,1":@"iPod Touch 3G", + @"iPod4,1":@"iPod Touch 4G", + @"iPod5,1":@"iPod Touch 5G", + //iPad + @"iPad1,1":@"iPad", + @"iPad2,1":@"iPad 2 (WiFi)", + @"iPad2,2":@"iPad 2 (GSM)", + @"iPad2,3":@"iPad 2 (CDMA)", + @"iPad2,4":@"iPad 2 (32nm)", + @"iPad2,5":@"iPad mini (WiFi)", + @"iPad2,6":@"iPad mini (GSM)", + @"iPad2,7":@"iPad mini (CDMA)", + @"iPad4,4":@"iPad mini 2", + @"iPad4,5":@"iPad mini 2", + @"iPad4,6":@"iPad mini 2", + @"iPad4,7":@"iPad mini 3", + @"iPad4,8":@"iPad mini 3", + @"iPad4,9":@"iPad mini 3", + @"iPad3,1":@"iPad 3(WiFi)", + @"iPad3,2":@"iPad 3(CDMA)", + @"iPad3,3":@"iPad 3(4G)", + @"iPad3,4":@"iPad 4 (WiFi)", + @"iPad3,5":@"iPad 4 (4G)", + @"iPad3,6":@"iPad 4 (CDMA)", + @"iPad4,1":@"iPad Air", + @"iPad4,2":@"iPad Air", + @"iPad4,3":@"iPad Air", + @"iPad5,3":@"iPad Air 2", + @"iPad5,4":@"iPad Air 2", + //模拟器 + @"i386":@"iPhone Simulator", + @"x86_64":@"iPhone Simulator", + }; + } + return mapping[deviceString]?mapping[deviceString]:@"iPhone"; +} + ++(NSString *)deviceCode{ + struct utsname systemInfo; + uname(&systemInfo); + NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + return deviceString; +} + + + + + + +@end