关于iOS GYDataCenter本地数据库解决方案的那些事儿--下卷

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27339239/article/details/55099619

之前的博客讲解了如何保存用户的敏感信息和如何使用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数据库使用了。



猜你喜欢

转载自blog.csdn.net/qq_27339239/article/details/55099619