关于iOS GYDataCenter本地数据库解决方案的那些事儿--下卷
2017-02-14 15:09
1021 查看
之前的博客讲解了如何保存用户的敏感信息和如何使用GYDataCenter创建数据库和数据表,这一篇主要谈一谈在开发中经常用的增删查改解决方案。
3.如何进行增删查改
先来查看一下GY的头文件,在GYDataCenter.h里面只有两个头文件。这里我们就知道了,外部主要使用的就只有GYDataContent和GYModelObject这两个类的内容,上一次在创建表格的时候就是继承了GYModelObject,从字面上理解,我们的数据库操作就应该属于GYDataContext的内容了。
#import <Foundation/Foundation.h> #import "GYDBRunner.h" @protocol GYModelObjectProtocol; @interface GYDataContext : NSObject + (GYDataContext *)sharedInstance; /** * * @param modelClass Class of the model object that you want to fetch. * 需要查询的数据类型,在这里就是需要操作的数据表 * @param properties Properties you need. Pass nil to get values of all properties. * 需要查询的表格中的字段,如果传入空的Array,返回所有的属性 * @param primaryKey Primary key value of the model object that you want to fetch. * 需要查询的数据的主键 * @return Object that match the primary key value, or nil if none is found. * 返回传入的表格的对象,对象内持有传入的字段的值 */ - (id)getObject:(Class<GYModelObjectProtocol>)modelClass properties:(NSArray *)properties primaryKey:(id)primaryKey; /** * * @param modelClass Class of the model objects that you want to fetch. * 需要查询的数据类型,在这里就是需要操作的数据表 * @param properties Properties you need. Pass nil to get values of all properties. * 需要查询的表格中的字段,如果传入空的Array,返回所有的属性 * @param where Where clause of SQL. Use '?'s as placeholders for arguments. * 这里传入SQL语句,格式为“where........” 这里是SQL中的条件语句 * @param arguments Values to bind to the where clause. * 上述SQL语句对应的Value * @return Objects that match the condition of the where clause. * 返回传入的表格的对象,对象内持有传入的字段的值 */ - (NSArray *)getObjects:(Class<GYModelObjectProtocol>)modelClass properties:(NSArray *)properties where:(NSString *)where arguments:(NSArray *)arguments; /** Join two tables. * 连标查询 * @param leftClass Class of the first join table. * 第一个关联的表格,一般为父表 * @param leftProperties Properties of leftClass that you need. Pass nil to get values of all properties. * 第一个表格的字段,一般为父表的字段,如果传入空的Array,返回所有的属性 * @param rightClass Class of the second join table. * 关联的第二个表格,一般为子表 * @param rightProperties Properties of rightClass that you need. Pass nil to get values of all properties. * 关联的字表的字段,一般为字表的字段, 如果传入空的Array,返回所有的属性 * @param joinType GYSQLJoinTypeInner, GYSQLJoinTypeLeft or GYSQLJoinTypeCross. * 两个表关联的方式 * @param joinCondition Join condition. For example: 'leftTableName.property1 = rightTableName.property2'. * 关联的字段 * @param where Where clause of SQL. Use '?'s as placeholders for arguments. * 这里传入SQL语句,格式为“where........” 这里是SQL中的条件语句 * @param arguments Values to bind to the where clause. * 上述SQL语句对应的Value * @return @[ @[`Objects of left class`], @[`objects of right class`] ]. * 返回传入的表格的对象的数组,对象内持有传入的字段的值 */ - (NSArray *)getObjects:(Class<GYModelObjectProtocol>)leftClass properties:(NSArray *)leftProperties objects:(Class<GYModelObjectProtocol>)rightClass properties:(NSArray *)rightProperties joinType:(GYSQLJoinType)joinType joinCondition:(NSString *)joinCondition where:(NSString *)where arguments:(NSArray *)arguments; /** * * @param modelClass Class of the model objects that you want to query. * 需要查询的数据类型,在这里就是需要操作的数据表 * @param where Where clause of SQL. Use '?'s as placeholders for arguments. * 这里传入SQL语句,格式为“where........” 这里是SQL中的条件语句 * @param arguments Values to bind to the where clause. * 上述SQL语句对应的Value * @return Primary key values that match the condition of the where clause. * 返回一组表对象 */ - (NSArray *)getIds:(Class<GYModelObjectProtocol>)modelClass where:(NSString *)where arguments:(NSArray *)arguments; /** * * @param modelClass Class of the model objects that you want to query. * 需要查询的数据类型,在这里就是需要操作的数据表 * @param function Aggregate function. For example: 'count(*)', 'sum(value)'... * 用于来统计 * @param where Where clause of SQL. Use '?'s as placeholders for arguments. * 这里传入SQL语句,格式为“where........” 这里是SQL中的条件语句 * @param arguments Values to bind to the where clause. * 上述SQL语句对应的Value * @return Result of the aggregate function. * 返回统计结果 */ - (NSNumber *)aggregate:(Class<GYModelObjectProtocol>)modelClass function:(NSString *)function where:(NSString *)where arguments:(NSArray *)arguments; /** * * @param object The object to be saved. * 保存表数据 */ - (void)saveObject:(id<GYModelObjectProtocol>)object; /** *清除某张表的所有数据 * */ - (void)deleteObject:(Class<GYModelObjectProtocol>)modelClass primaryKey:(id)primartyKey; /** * * @param modelClass Class of the model objects that you want to delete. * 需要删除数据表格 * @param where Where clause of SQL. Use '?'s as placeholders for arguments. * 需要删除的条件 * @param arguments Values to bind to the where clause. * 需要删除条件的值 */ - (void)deleteObjects:(Class<GYModelObjectProtocol>)modelClass where:(NSString *)where arguments:(NSArray *)arguments; /** * * @param modelClass Class of the model object that you want to update. * 需要更新的表 * @param set Property and new value pairs. * 需要更新的内容,这里传入一个字典 * @param primaryKey Primary key value of the model object that you want to update. * 主键 */ - (void)updateObject:(Class<GYModelObjectProtocol>)modelClass set:(NSDictionary *)set primaryKey:(id)primaryKey; /** * * @param modelClass Class of the model object that you want to update. * 需要更新的表 * @param set Property and new value pairs. * 需要更新的内容,这里传入一个字典 * @param primaryKey Primary key value of the model object that you want to update. * 主键 * @return A new updated object. * 返回更新后的对象 */ - (id)updateAndReturnObject:(Class<GYModelObjectProtocol>)modelClass set:(NSDictionary *)set primaryKey:(id)primaryKey; /** * * @param modelClass Class of the model objects that you want to update. * 需要更新的表 * @param set Property and new value pairs. * 需要更新的内容,这里传入一个字典 * @param where Where clause of SQL. Use '?'s as placeholders for arguments. * 需要更新的SQL,这里是条件语句 * @param arguments Values to bind to the where clause. * SQL语句对应的值 */ - (void)updateObjects:(Class<GYModelObjectProtocol>)modelClass set:(NSDictionary *)set where:(NSString *)where arguments:(NSArray *)arguments; //创建一个数据库事务 - (void)inTransaction:(dispatch_block_t)block dbName:(NSString *)dbName; - (void)vacuumAllDBs; - (void)synchronizeAllData; @end
现在上面的方法进行逐一讲解:
这里我们需要理解的一点,我们不需要直接调用上面的方法,在我们创建数据表的时候,那一个表模型就封装了一层,直接调用模型表的方法就行了。
a.增删查改--查,查询在这个数据库中是很重要的。
/* @method queryAllContactsInfos @abstrac 查询所有联系人信息 @discussion 查询所有联系人信息 @param No param @result @[QYJContactsInfo, ...] */ + (NSArray *)queryAllContactsInfos { NSMutableArray *results = nil; NSString *where = @"";//这里查询所有的标中的数据,不需要额外的条件,故传null NSArray *arguments = nil;//上面SQL是NULL,所以这里传入一个nil,sql的中的'?'占位符与数组的个数对应 /** * 此处如果需要对查获的数据进行出库的时候的排序可以使用ORDER BY (order by) * ASC 为升序, DESC 为降序, 不写默认为升序,不使用order by按自增ID排序输出 * e.g: * NSString *where = @"ORDER BY name";//按名字升序 * NSString *where = @"ORDER BY name, phoneNum DESC"//先按名字升序,再按电话号码降序 * NSString *where = @"ORDER BY name DESC, phoneNum"//先按名字降序,再按电话号码升序 * 其他查询的写法和SQL语句一致 * "where name = ? ORDER BY nameFirstLetter" * "where name = ? AND phoneNum ORDER BY name"; */ results = [QYJContactsInfo objectsWhere:where arguments:arguments].mutableCopy; return results; } /* @method queryContactsInfoByName: @abstrac 根据姓名去查询联系人 @discussion 根据姓名去查询联系人 @param name NSString @result @[QYJContactsInfo, ...] */ + (NSArray *)queryContactsInfoByName:(NSString *)name { //手机联系人可能存在同名的 NSMutableArray *results = nil; /** * 如果需要多个查询的条件用AND来连接 * e.g: 根据姓名和号码查询 * NSString *where = @"WHERE name = ? AND phoneNum = ?"; * NSArray *arguments = @[name, phoneNum]; * * 如果需要模糊查询用%%来表示,这OC中%需要转译 * e.g: * NSString *where = @"WHERE name LIKE '%%?%%'"; * NSArray *arguments = @[name]; * OR * NSString *where = [NSString stringWithFormat:@"WHERE name LIKE '%%%@%%'", name]; * * 如果需要满足任意条件的数据使用OR来连接 * e.g: * NSString *where = @"WHERE name = ? OR phoneNum = ?" * NSArray *arguments = @[name, phoneNum]; */ NSString *where = @"WHERE name = ?"; NSArray *arguments = @[name]; results = [QYJContactsInfo objectsWhere:where arguments:arguments].mutableCopy; return results; }
b.增删查改--改,改就是更新,这里的原则是能在库里面修改的数据,就不要拿出数据库来。
/* @method updateContactsInfoByName:set: @abstrac 按名字修改对应的字段的数据 @discussion 按名字修改对应的字段的数据 @param name NSString set NSDictionary @result No result */ + (void)updateContactsInfoByName:(NSString *)name set:(NSDictionary *)set { /** * 假定 name为Avalanching, set 是 @{@"phoneNum":@"11111111"}; * 将数据表中name为Avalanching 的 phoneNum 的值改为 "11111111" */ NSString *where = @"WHERE name = ?"; NSArray *arguments = @[name]; //不会返回更新后的数据 [QYJContactsInfo updateObjectsSet:set Where:where arguments:arguments]; } /* @method updateContactsInfoByInfo:set: @abstrac 将需要修改的QYJContactsInfo对象和修改的数据传入,更新表数据 @discussion 将需要修改的QYJContactsInfo对象和修改的数据传入,更新表数据 @param info QYJContactsInfo set NSDictionary @result No result */ + (void)updateContactsInfoByInfo:(QYJContactsInfo *)info set:(NSDictionary *)set { //这里直接用到GYDataContext的方法,要引入GYDataContext.h //这里是更新QYJContactsInfo中 primaryKeyId 等于 info.primaryKeyId 的数据 [[GYDataContext sharedInstance] updateObject:[info class] set:set primaryKey:@(info.primaryKeyId)]; //这里是更新QYJContactsInfo中 primaryKeyId 等于 info.primaryKeyId 的数据 并返回新的对象 QYJContactsInfo *newinfo = [[GYDataContext sharedInstance] updateAndReturnObject:[info class] set:set primaryKey:@(info.primaryKeyId)]; //将表中满足条件的数据全部更新成set中的数值 NSString *where = @"WHERE name = ?"; NSArray *arguments = @[info.name]; [[GYDataContext sharedInstance] updateObjects:[info class] set:set where:where arguments:arguments]; }
c.增删查改--删,删除(逻辑删除和物理删除)
这里首先要明确,逻辑删除不是删除,仅仅是将数据库中的数据状态改变一下,逻辑删除根据数据库结构来定的,这里不做讲解;物理删除就将数据彻底从数据库中移除。/* @method cleanContactsInfos @abstrac 清空通讯录表格里面所有的数据 @discussion 清空通讯录表格里面所有的数据 @param No param @result No result */ + (void)cleanContactsInfos { NSString *where = @""; //清除所有数据,不填写任何条件 NSArray *arguments = nil; /** * 按条件删除 * where = @"WHERE name = ?"; * argument = @[name]; */ [[GYDataContext sharedInstance] deleteObjects:[QYJContactsInfo class] where:where arguments:arguments]; //根据primaryKeyId去删除数据 [[GYDataContext sharedInstance] deleteObject:[QYJContactsInfo class] primaryKey:@(1)]; } /* @method deleteContactsInfosByInfo: @abstrac 删除某一条数据 @discussion 删除数据 @param info QYJContactsInfo @result No result */ + (void)deleteContactsInfosByInfo:(QYJContactsInfo *)info { [info deleteObject]; }
d.其他,开发中经常用到一些问题。
1.特殊字符的转译查询的问题,'%', ' ' ' , '/'等等。
/* @method queryContactsInfoBySpecialCharacter: @abstrac 查询包含特殊字符的数据 (_, %, /, \, *) @discussion 查询包含特殊字符的数据 (_, %, /, \, *) @param character 特殊字符 @result NSArray<QYJContactsInfo *> * */ + (NSArray<QYJContactsInfo *> *)queryContactsInfoBySpecialCharacter:(NSString *)character { //使用escape关键字和[]来转译查询 /, *, %这一类的关键字 //NSString *where = [NSString stringWithFormat:@"WHERE name LIKE '[%@]'", character]; NSString *where = [NSString stringWithFormat:@"WHERE name LIKE '%%*%@%%' escape'*' ORDER BY namePinyin", character]; NSArray *arguments = nil; return [QYJContactsInfo objectsWhere:where arguments:arguments]; }2.链表查询
/* @method associationQuery @abstrac 关联查询 @discussion 关联查询 @param No param @result No result */ + (NSArray *)associationQuery { NSString *where = @""; NSArray *arguments = @[]; //这里只创建了一张表,所以两个表都写为[QYJContactsInfo class], 实际开发是两张不同的表格 NSArray *result = [[GYDataContext sharedInstance] getObjects:[QYJContactsInfo class] properties:nil objects:[QYJContactsInfo class] properties:nil joinType:GYSQLJoinTypeInner joinCondition:@"这里是相关联的字段" where:where arguments:arguments]; //如果不能理解这查询的方式,可以先查一张表,再把查处来的表格,再查另外一张表 return result; }3.索引表的快速删除
#define Local_Tabel @"IndexesTabel" #define dbPath @"这里是数据库的路径" #define local_dbQueue [FMDatabaseQueue databaseQueueWithPath:dbPath] + (void)updateIndexesTabelByCondition:(NSString *)condition { //这里需要直接写SQL,所以这里需要用底层的FMDB // 一般索引表都是存一个id, ids 字段 对应的只为"1, 2, 3, 4, 5, 6"; // id 为4 的数据已经从主表中删除了,现在要修改ids含有4的数据,将4去除 // 才用replace关键字去替代,一次替代之后有可能出现的情况是 // "1, 2, 3, 4, 5" =(第一次replace)=> "1, 2, 3, ,5" // "4, 5, 6" =(第一次replace)=> ",5,6" // "1, 2, 3, 4" =(第一次replace)=> "1, 2, 3," //后面两条SQL 用于修改正 数据库里面的结构 NSString * sql = [NSString stringWithFormat:@"UPDATE %@ SET schedule_id = REPLACE(schedule_id, ?, '')", Local_Tabel]; NSString * sqlDetele = [NSString stringWithFormat:@"DELETE FROM %@ WHERE schedule_id = ','", Local_Tabel]; NSString * sqlRepace = [NSString stringWithFormat:@"UPDATE %@ SET schedule_id = REPLACE(schedule_id, ',,', ',')", Local_Tabel]; [local_dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:sql, condition]; [db executeUpdate:sqlRepace]; [db executeUpdate:sqlDetele]; }]; }
4.数据迁移
这里不提供具体代码,只提供思路,最简单的做法就是从将旧的数据从数据库中取出来,然后组建成新的数据格式存入新的表格,这里我们上次提到了一个重写 - (BOOL)isEqual:(id)object的方法,这里可以通过NSArray转NSSet的方式过滤掉重复的数据,具体判断相等的规则就又开发者根据具体的情况去定了。
一般常规开发中升级数据库,需要将旧的表格的数据取出来,然后创建新表格去存放,小版本的升级就要避免迁移的时候修改很多,这里就要让旧表和新表名字保持一致,将操作放到一个事务里面去处理。
这些就是简单的GYDataCenter数据库使用了。
相关文章推荐
- 关于iOS GYDataCenter本地数据库解决方案的那些事儿--上卷
- 关于“System.Data.OleDb.OleDbException,外部数据库驱动程序 (1) 中的意外错误。”的解决方案
- 关于“System.Data.OleDb.OleDbException,外部数据库驱动程序 (1) 中的意外错误。”的解决方案
- 关于 iOS 5 里无法取得 UUID 的一个解决方案
- 关于跳过flex的sandbox实现访问本地资源的解决方案
- 创建本地数据库时发生错误及其解决方案
- 分页解决方案 —— GridView + QuickPager + QuickPager_SQL + DataAccessLibrary + 数据库
- 关于在设计SqlDataAdapter并使用带有参数的 SQL或存储过程时,出现的必须声明 @参数名 的错误解决方案
- 一起谈.NET技术,关于Windows Phone数据库和Silverlight本地文件操作
- 关于“因为数据库正在使用,所以无法获得对数据库的独占访问权”的最终解决方案
- 关于“因为数据库正在使用,所以无法获得对数据库的独占访问权”的最终解决方案
- 关于数据库还原时出现的因为数据库正在使用,所以无法获得对数据库的独占访问权“的解决方案
- 关于数据库被锁定的问题及其解决方案
- js本地存储解决方案(localStorage与userData)
- 关于数据库查询语句SqlDataReader的连接释放问题的解决办法
- 关于Windows Phone数据库和Silverlight本地文件操作
- 关于使用dataAdapter.acceptChanges( )方法更新dataSet和数据库的问题
- ASP页面将数据库中检索数据生成到本地报表的解决方案
- 关于Orcale数据库控制台无法启动解决方案
- 关于在Asp.net下使用Oracle.DataAccess.dll(Oracle10g)执行参数化Update无效的解决方案之一