您的位置:首页 > 数据库

关于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数据库使用了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐