在实际开发中,数据库存储只会用到那几个增删改查SQL语句,不会用到多表查询啊,多种条件增删改啊。所以写这个东西的目的,是把这几个SQL语句封装起来,在开发中操作数据库就省去写了SQL语句的麻烦。可能中间有些写得不够好,有兴趣的大虾过来指点指点小弟。
我们保存model,无非就是把所有的model装到一个数据里面,把数据直接塞进数据库里面即可。
创建SQL语句要得到model的键和值。这里使用RunTime方法来获取model的属性。下面是核心代码
// model的属性作为表的列名
// 可以通过RunTime的方法来获取model的属性
// model属性的个数
unsigned int propertyCount = 0;
// 通过运行时获取model的属性 这里要导入 #import <objc/runtime.h>
objc_property_t *propertys = class_copyPropertyList([model class], &propertyCount);
for (int i = 0; i < propertyCount; i ++) {
// 取出元素
objc_property_t property = propertys[i];
// 得到的是char*型的
const char *propertyName = property_getName(property);
// 转化
NSString *OCString = [NSString stringWithUTF8String:propertyName];
// NSLog(@"%@", OCString);
操作数据库分几个步骤
1. 创建数据库
……
#define FMDBManager [LJXFMDBManager ShareFMDBManager]
……
// 一般保存到cache目录里面
NSString *dataPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
dataPath = [dataPath stringByAppendingPathComponent:@"MyDB.sqlite"];
// 创建数据库
[FMDBManager createDataBaseWithPath:dataPath];
为了让这过程中都能看到数据库的东西,我们用SQLiteManager去下载SQLiteManager
打开数据库文件,首先我们得找到这个文件。我在这文章里有打开真机caches文件里的方法。
http://blog.csdn.net/u010971348/article/details/53290523
打开caches目录后,可以看到创建的sqlite文件,安装了SQLiteManager的话,默认打开方式就是SQLiteManager了。又击它,没创表的时候,当然是空的,我这里创建了表,
创建表代码, 为了方便操作,传一个主键过去。(不设置主键的我也写过了,结果,操作麻烦,比如插入会有重复的model,要解决这个问题,就要在插入之前查一下表,看要插入的model存不存在,存在的话就替换,不存在的话就插入,这样子太浪更内存了)
调用方法
NSString *tableName =_tableName.text;
Class modelClass = [CheckinModel class];
if ([FMDBManager createTableWithName:tableName model:modelClass primaryKey:@"flightCode"]) {
[self showMessage:@"创表成功"];
} else {
[self showMessage:@"创表失败"];
}
/**
创建表
@param tableName 表名
@param primaryKey 设置主键以便操作
@return 创建表是否成功
*/
- (BOOL)createTableWithName:(NSString *)tableName model:(Class)model primaryKey:(NSString *)primaryKey;
- (BOOL)createTableWithName:(NSString *)tableName model:(Class)model primaryKey:(NSString *)primaryKey
{
if (self.dataBase) {
// 打开数据库
[self.dataBase open];
// 判断表是否存在
BOOL success = [self.dataBase tableExists:tableName];
if (success) {
// 存在就不用创建了,操作完成。记得关闭数据库
[self.dataBase close];
return YES;
} else {
// 不存在的话,
// 创建SQL语句;
NSString *SQLString = [self createTableSQLString:model tableName:tableName primaryKey:primaryKey];
if ([self.dataBase executeUpdate:SQLString]) {
// 创建表成功,关闭
[self.dataBase close];
return YES;
} else {
return NO;
}
}
} else {
NSLog(@"数据库不存在");
return NO;
}
}
// 创表语句
- (NSString *)createTableSQLString:(id)model tableName:(NSString *)tableName primaryKey:(NSString *)primaryKey
{
// 为了提交表数据的容错性,都用text 类型
NSString *sqliteString = [NSString stringWithFormat:@"create table if not exists %@ (%@ text primary key", tableName, primaryKey];
// model的属性作为表的列名
// 可以通过RunTime的方法来获取model的属性
// model属性的个数
unsigned int propertyCount = 0;
// 通过运行时获取model的属性 这里要导入 #import <objc/runtime.h>
objc_property_t *propertys = class_copyPropertyList([model class], &propertyCount);
for (int i = 0; i < propertyCount; i ++) {
// 取出元素
objc_property_t property = propertys[i];
// 得到的是char*型的
const char *propertyName = property_getName(property);
// 转化
NSString *OCString = [NSString stringWithUTF8String:propertyName];
// NSLog(@"%@", OCString);
// 如果是主键的话,就不用拼接上去了,因为一开始就拼了
if (![OCString isEqualToString:primaryKey]) {
// 拼接
if (i == 0) {
sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@"%@ text", OCString]];
} else {
sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@", %@ text", OCString]];
}
}
}
sqliteString = [sqliteString stringByAppendingString:@")"];
return sqliteString;
}
创建表成功后,我们可以在那个sqlite文件里面看到这些东西,可以看到,表的列名就是model的属性名,除了前面的那个rowid是自己本来就有的
接下来就是插入model了。
NSMutableArray *muta = [NSMutableArray array];
NSString *path = [[NSBundle mainBundle] pathForResource:@"checkin" ofType:@"json"];
NSData *jsData = [NSData dataWithContentsOfFile:path];
NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsData options:NSJSONReadingMutableContainers error:nil];
NSArray *dataArray = dataDic[@"data"];
for (NSDictionary *subDic in dataArray) {
CheckinModel *model = [CheckinModel initWithDic:subDic];
[muta addObject:model];
}
/// 插入
if ([FMDBManager insterModelArray:muta toTable:_tableName.text]) {
[self showMessage:@"插入成功"];
NSArray *all = [FMDBManager searchAllModel:[CheckinModel class] tableName:_tableName.text];
[_dataArray removeAllObjects];
[_dataArray addObjectsFromArray:all];
[self.tableView reloadData];
NSLog(@"个数%ld", all.count);
} else {
[self showMessage:@"插入失败"];
}
/**
插入 模型 数组
@param modelArray 模型数组
@param tableName 表名
@return 插入是否成功
*/
.h里面
- (BOOL)insterModelArray:(NSArray *)modelArray toTable:(NSString *)tableName;
.m里面
// 插入一组
- (BOOL)insterModelArray:(NSArray *)modelArray toTable:(NSString *)tableName
{
if (self.dataBase) {
// 凡事先打开数据库
[self.dataBase open];
if ([self.dataBase tableExists:tableName]) {
NSString *sqlString = @"";
for (NSInteger i = 0; i < modelArray.count; i ++) {
// 拼接sql语句
NSString *subString = [self insertSQLStringWith:modelArray[i] tableName:tableName];
if (i == 0) {
sqlString = [sqlString stringByAppendingString:subString];
} else {
sqlString = [sqlString stringByAppendingFormat:@"; %@", subString];
}
}
// 多行执行
BOOL success = [self.dataBase executeStatements:sqlString];
[self.dataBase close];
return success;
}else {
// 表不存在
NSLog(@"插入失败,表不存在");
[self.dataBase close];
return NO;
}
} else {
// 数据库都不存在,先去创建数据库吧
NSLog(@"数据库不存在");
return NO;
}
}
// 插入数据语句
- (NSString *)insertSQLStringWith:(id)model tableName:(NSString *)tableName
{
NSString *sqliteString = [NSString stringWithFormat:@"insert or replace into %@ (", tableName];
// 一般是以model的属性作为表的列名
// 可以通过RunTime的方法来获取model的属性
// model属性的个数
unsigned int propertyCount = 0;
// 通过运行时获取model的属性 这里要导入 #import <objc/runtime.h>
objc_property_t *propertys = class_copyPropertyList([model class], &propertyCount);
// 装属性的数组
NSMutableArray *keyArray = [NSMutableArray array];
for (int i = 0; i < propertyCount; i ++) {
// 取出元素
objc_property_t property = propertys[i];
const char *propertyName = property_getName(property);
// 转化
NSString *OCString = [NSString stringWithUTF8String:propertyName];
NSString *valueString = [NSString stringWithFormat:@"%@",[model valueForKey:OCString]];
if (valueString.length > 0) {
// 如果model的属性没有值的话,那就不加操作那列值了
// 保存键
[keyArray addObject:OCString];
// 拼接
if (i == 0) {
sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@"'%@'",OCString]];
} else {
sqliteString = [sqliteString stringByAppendingString:[NSString stringWithFormat:@", '%@'", OCString]];
}
}
}
sqliteString = [sqliteString stringByAppendingString:@") values ("];
// 值
for (int i = 0; i < keyArray.count; i ++) {
NSString *key = keyArray[i];
NSString *keyString;
// 拼接 记得加单引号
if (i == 0) {
keyString = [NSString stringWithFormat:@"'%@'", [model valueForKey:key]];
} else {
keyString = [NSString stringWithFormat:@", '%@'", [model valueForKey:key]];
}
sqliteString = [sqliteString stringByAppendingString:keyString];
}
//
sqliteString = [sqliteString stringByAppendingString:@")"];
return sqliteString;
}
执行完后,再看看sqlite里面
用得最多的就是这个插入方法了,因为他也是更新方法,你随便插入model,不过要是那一类model,如果里面有相同的话,他会直接替换掉,我这里用的SQL语句是
insert or replace into 避免他有重复的model。
还有更他的方法
**
查询某条数据所在的model。比如学号(key)为2001(vlaue)的model
@param model 所查model类型
@param keyString 所查的键
@param valueString 所查的值
@param tableName 所查的表
@return 返回的model数组
*/
- (NSArray *)searchModel:(Class)model WithKey:(NSString *)keyString value:(NSString *)valueString inTable:(NSString *)tableName;
/**
查询所有的model
@param modelClass 所查的model类型
@param tableName 表名
@return 所有的model
*/
- (NSArray *)searchAllModel:(Class)modelClass tableName:(NSString *)tableName;
#pragma mark - 删除
/**
删除表中所有的数据, 不删除表, 但不删除列名
@param tableName 表名
@return 是否删除成功
*/
- (BOOL)truncateTable:(NSString *)tableName;
/**
删除整个表
@param tableName 表名
@return 是否删除成功
*/
- (BOOL)dropTable:(NSString *)tableName;
/**
删除指定条件的model
如:删除学号 为 2002的model
@param columnName 指定列名
@param columnValue 指定列值
@param tableName 表名
@return 删除成功与否
*/
- (BOOL)deleteModelColumnName:(NSString *)columnName columnValue:(NSString *)columnValue tableName:(NSString *)tableName;
都写进去了,demo请移步gitHub