Coder Social home page Coder Social logo

netyouli / whc_modelsqlitekit Goto Github PK

View Code? Open in Web Editor NEW
617.0 30.0 151.0 243 KB

专业的ORM数据库操作开源库,线程安全,高性能模型对象存储Sqlite开源库,真正实现一行代码操作数据库,让数据库存储变得简单 Professional database storage solutions, thread safe, high-performance model object storage Sqlite open source library, realize one line of code database operation, simple database storage

Home Page: http://www.wuhaichao.com

License: MIT License

Objective-C 99.30% Ruby 0.70%
whc sqlite db modelsqlite fmdb realm

whc_modelsqlitekit's Introduction

WHC_ModelSqliteKit

Build Status Pod Version Pod Platform Pod License

架构图


  • Professional database storage solutions, thread safe, high-performance model object storage Sqlite open source library, realize one line of code database operation, simple database storage
  • 专业的数据库存储解决方案,线程安全,高性能模型对象存储Sqlite开源库,真正实现一行代码操作数据库,让数据库存储变得简单

简介

  • 架构: 采用runtime和Sqlite完美结合打造的强大数据库ORM操作引擎开源库
  • 安全: 支持数据库级别加密
  • 易用: 真正实现一行代码操作数据库
  • 目标: 替代直接使用Sqlite和CoreData以及FMDB低效率方式
  • 支持: (NSMutableDictionary,NSMutableArray,NSArray,NSDictionary,NSDate,NSData,NSString,NSNumber,Int,double,float,Bool,char)类型
  • 灵活: 支持使用Sqlite函数进行查询,支持忽略模型类属性存储数据表中
  • 兼容: 支持模型嵌套继承模型类存储到数据库和多表嵌套复杂查询
  • 智能: 根据数据库模型类实现的WHC_SqliteInfo协议返回的版本号来智能更新数据库字段(动态删除/添加)

修复升级: 修复子模型对象为nil访问子模型属性崩溃bug

修复升级: 兼容支持存储NSMutableDictionary, NSMutableArray类型

修复升级: 支持自定义数据库存储路径

升级功能: 支持WHCSqlite操作使用其他方式创建的数据库比如FMDB,只需要指定数据库存储路径。 如果表名不是模型类名称需要指定表名, 详细使用可以参考提供demo,和WHC_SqliteInfo协议

多表嵌套复杂查询

/// 查询person名称为吴海超,并且person的汽车对象的名称为宝马或者person对象学校对象的所在城市对象的名称为北京
NSArray * result = [WHCSqlite query:[Person class] 
        where:@"name = '吴海超' and car.name = '宝马' or school.city.name = '北京'"];

自定义sql查询

persons = [WHCSqlite query:Person.self sql:@"select * from Person"];

/// 来个复杂的例如:
[WHCSqlite query:Model.self sql:@"select cc.* from 
     ( select tt.*,(select count(*)+1 from Chapter where chapter_id =tt.chapter_id and updateTime<tt.updateTime ) as group_id from Chapter tt)
     cc where cc.group_id<=7 order by updateTime desc"];

要求

  • iOS 5.0 or later
  • Xcode 8.0 or later

集成

  • 不需要加密使用: pod 'WHC_ModelSqliteKit'
  • 需要加密数据库使用: pod 'WHC_ModelSqliteKit/SQLCipher'

注意

  • 在需要对数据表自定义信息需要model类实现WHC_SqliteInfo协议
  • 当模型类有新增/删除属性的时候需要在模型类里定义类方法whc_SqliteVersion方法修改模型类(数据库)版本号来表明有字段更新操作,库会根据这个VERSION变更智能检查并自动更新数据库字段,无需手动更新数据库字段
  • 当存储NSArray/NSDictionary属性并且里面是自定义模型对象时,模型对象必须实现NSCoding协议,可以使用WHC_Model库一行代码实现NSCoding相关代码
  • 当需要模型类忽略属性存储数据表时实现whc_IgnorePropertys协议方法即可return要忽略属性名称数组
  • 好用的Mac开源工具:Json生成Class,扫描无用图片,扫描无用类,keyborad
  • 如果要获取主键id值需要在model里声明属性:@property (nonatomic, assign) NSInteger whcId; 或者自定义主键名称的属性
/// 数据库协议信息
@protocol WHC_SqliteInfo <NSObject>
@optional
/**
自定义数据存储路径
@return 自定义数据库路径(目录即可)
*/
+ (NSString *)whc_SqlitePath;

/// 自定义模型类数据库版本号
/** 注意:
***该返回值在改变数据模型属性类型/增加/删除属性时需要更改否则无法自动更新原来模型数据表字段以及类型***
*/
+ (NSString *)whc_SqliteVersion;

/// 自定义数据库加密密码
/** 注意:
***该加密功能需要引用SQLCipher三方库才支持***
/// 引入方式有:
*** 手动引入 ***
*** CocoaPods: pod 'WHC_ModelSqlite/SQLCipher' ***
*/
+ (NSString *)whc_SqlitePasswordKey;

/// 自定义数据表主键名称
/**
*** 返回自定义主键名称默认主键:_id ***
*/
+ (NSString *)whc_SqliteMainkey;

/**
忽略属性集合

@return 返回忽略属性集合
*/
+ (NSArray *)whc_IgnorePropertys;


/**
引入使用其他方式创建的数据库存储路径比如:FMDB
来使用WHC_Sqlite进行操作其他方式创建的数据库

@return 存储路径
*/
+ (NSString *)whc_OtherSqlitePath;


/**
指定自定义表名

在指定引入其他方式创建的数据库时,这个时候如果表名不是模型类名需要实现该方法指定表名称

@return 表名
*/
+ (NSString *)whc_TableName;

@end

用法

1.存储嵌套模型对象到数据库演示

Person * whc = [Person new];
whc.name = @"吴海超";
whc.age = 25;
whc.height = 180.0;
whc.weight = 140.0;
whc.isDeveloper = YES;
whc.sex = 'm';

// 嵌套car对象
whc.car = [Car new];
whc.car.name = @"撼路者";
whc.car.brand = @"大路虎";

// 嵌套school对象
whc.school = [School new];
whc.school.name = @"北京大学";
whc.school.personCount = 5000;

// school对象嵌套city对象
whc.school.city = [City new];
whc.school.city.name = @"北京";
whc.school.city.personCount = 1000;

/// 测试NSArray属性存储
Car * tempCar = [Car new];
tempCar.name = @"宝马";
tempCar.brand = @"林肯";
whc.array = @[@"1",@"2"];
whc.carArray = @[tempCar];

/// 测试NSDictionary属性存储
whc.dict = @{@"1":@"2"};
whc.dictCar = @{@"car": tempCar};

[WHCSqlite insert:whc];

2.存储批量模型对象到数据库演示

NSArray * persons = [self makeArrayPerson];
[WHCSqlite inserts:persons];

3.无条件查询(查询所有记录)数据库中模型类演示

NSArray * personArray = [WHCSqlite query:[Person class]];

3.1.使用Sqlite函数查询数据库演示

/// 获取Person表所有name和name长度
NSArray * nameArray = [WHCSqlite query:[Person class] func:@"name, length(name)"];
NSLog(@"nameArray = %@",nameArray);

/// 获取Person表最大age值
NSNumber * maxAge = [WHCSqlite query:[Person class] func:@"max(age)"];
NSLog(@"maxAge = %@",maxAge);

/// 获取Person表总记录数
NSNumber * sumCount = [WHCSqlite query:[Person class] func:@"count(*)"];
NSLog(@"sumCount = %@",sumCount);

/// 获取Person表字段school.city.name = 北京--0,总记录数
sumCount = [WHCSqlite query:[Person class] func:@"count(*)" condition:@"where school.city.name = '北京--0'"];
NSLog(@"sumCount = %@",sumCount);

4.条件查询数据库中模型类演示(where 条件查询语法和sql where条件查询语法一样)

NSArray * personArray = [WHCSqlite query:[Person class] where:@"name = '吴海超2' OR age <= 18"];

5.查询数据库并对结果排序

///对person数据表查询并且根据age自动降序或者升序排序
[WHCSqlite query:[Person class] order:@"by age desc/asc"];

6.查询数据库并对结果限制查询条数

/// 对person数据表查询并且并且限制查询数量为8
[WHCSqlite query:[Person class] limit:@"8"];

/// 对person数据表查询并且对查询列表偏移8并且限制查询数量为8
[WHCSqlite query:[Person class] limit:@"8 offset 8"];

7.修改数据库中模型对象演示(where 条件查询语法和sql where条件查询语法一样)

/// 更新整条记录
[WHCSqlite update:whc where:@"name = '吴海超2' OR age <= 18"];
/// 更新整条记录中的指定字段(更新Person表在age字段大于25岁时name值为whc,age为100岁)
[WHCSqlite update:Person.self value:@"name = 'whc', age = 100" where:@"age > 25"];

8.删除数据库中模型对象演示(where条件查询为空则删除所有)

[WHCSqlite delete:[Person class] where:@"age = 25 AND name = '吴海超'"];

9.清空指定数据库演示

[WHCSqlite clear:[Person class]];

10.删除数据库演示

[WHCSqlite removeModel:[Person class]];

11.删除所有数据库演示

[WHCSqlite removeAllModel];

12.获取数据库本地路径演示

NSString * path = [WHCSqlite localPathWithModel:[Person class]];

13.获取数据库本地版本号演示

NSString * path = [WHCSqlite versionWithModel:[Person class]];

期待

  • 如果您在使用过程中有任何问题,欢迎issue me! 很乐意为您解答任何相关问题!
  • 与其给我点star,不如向我狠狠地抛来一个BUG!
  • 如果您想要更多的接口来自定义或者建议/意见,欢迎issue me!我会根据大家的需求提供更多的接口!

Api文档

/**
* 说明: 存储模型数组到本地(事务方式)
* @param model_array 模型数组对象(model_array 里对象类型要一致)
*/

+ (BOOL)inserts:(NSArray *)model_array;

/**
* 说明: 存储模型到本地
* @param model_object 模型对象
*/

+ (BOOL)insert:(id)model_object;


/**
* 说明: 获取模型类表总条数
* @param model_class 模型类
* @return 总条数
*/
+ (NSUInteger)count:(Class)model_class;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @return 查询模型对象数组
*/

+ (NSArray *)query:(Class)model_class;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param where 查询条件(查询语法和SQL where 查询语法一样,where为空则查询所有)
* @return 查询模型对象数组
*/

+ (NSArray *)query:(Class)model_class where:(NSString *)where;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param order 排序条件(排序语法和SQL order 查询语法一样,order为空则不排序)
* @return 查询模型对象数组
*/

/// �example: [WHCSqlite query:[Person class] order:@"by age desc/asc"];
/// 对person数据表查询并且根据age自动降序或者升序排序

+ (NSArray *)query:(Class)model_class order:(NSString *)order;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param limit 限制条件(限制语法和SQL limit 查询语法一样,limit为空则不限制查询)
* @return 查询模型对象数组
*/

/// �example: [WHCSqlite query:[Person class] limit:@"8"];
/// 对person数据表查询并且并且限制查询数量为8
/// �example: [WHCSqlite query:[Person class] limit:@"8 offset 8"];
/// 对person数据表查询并且对查询列表偏移8并且限制查询数量为8

+ (NSArray *)query:(Class)model_class limit:(NSString *)limit;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param where 查询条件(查询语法和SQL where 查询语法一样,where为空则查询所有)
* @param order 排序条件(排序语法和SQL order 查询语法一样,order为空则不排序)
* @return 查询模型对象数组
*/

/// �example: [WHCSqlite query:[Person class] where:@"age < 30" order:@"by age desc/asc"];
/// 对person数据表查询age小于30岁并且根据age自动降序或者升序排序

+ (NSArray *)query:(Class)model_class where:(NSString *)where order:(NSString *)order;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param where 查询条件(查询语法和SQL where 查询语法一样,where为空则查询所有)
* @param limit 限制条件(限制语法和SQL limit 查询语法一样,limit为空则不限制查询)
* @return 查询模型对象数组
*/

/// �example: [WHCSqlite query:[Person class] where:@"age <= 30" limit:@"8"];
/// 对person数据表查询age小于30岁并且限制查询数量为8
/// �example: [WHCSqlite query:[Person class] where:@"age <= 30" limit:@"8 offset 8"];
/// 对person数据表查询age小于30岁并且对查询列表偏移8并且限制查询数量为8

+ (NSArray *)query:(Class)model_class where:(NSString *)where limit:(NSString *)limit;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param order 排序条件(排序语法和SQL order 查询语法一样,order为空则不排序)
* @param limit 限制条件(限制语法和SQL limit 查询语法一样,limit为空则不限制查询)
* @return 查询模型对象数组
*/

/// �example: [WHCSqlite query:[Person class] order:@"by age desc/asc" limit:@"8"];
/// 对person数据表查询并且根据age自动降序或者升序排序并且限制查询的数量为8
/// �example: [WHCSqlite query:[Person class] order:@"by age desc/asc" limit:@"8 offset 8"];
/// 对person数据表查询并且根据age自动降序或者升序排序并且限制查询的数量为8偏移为8

+ (NSArray *)query:(Class)model_class order:(NSString *)order limit:(NSString *)limit;

/**
* 说明: 查询本地模型对象
* @param model_class 模型类
* @param where 查询条件(查询语法和SQL where 查询语法一样,where为空则查询所有)
* @param order 排序条件(排序语法和SQL order 查询语法一样,order为空则不排序)
* @param limit 限制条件(限制语法和SQL limit 查询语法一样,limit为空则不限制查询)
* @return 查询模型对象数组
*/

/// �example: [WHCSqlite query:[Person class] where:@"age <= 30" order:@"by age desc/asc" limit:@"8"];
/// 对person数据表查询age小于30岁并且根据age自动降序或者升序排序并且限制查询的数量为8
/// �example: [WHCSqlite query:[Person class] where:@"age <= 30" order:@"by age desc/asc" limit:@"8 offset 8"];
/// 对person数据表查询age小于30岁并且根据age自动降序或者升序排序并且限制查询的数量为8偏移为8

+ (NSArray *)query:(Class)model_class where:(NSString *)where order:(NSString *)order limit:(NSString *)limit;


/**
说明: 自定义sql查询

@param model_class 接收model类
@param sql sql语句
@return 查询模型对象数组

/// �example: [WHCSqlite query:Model.self sql:@"select cc.* from ( select tt.*,(select count(*)+1 from Chapter where chapter_id =tt.chapter_id and updateTime<tt.updateTime ) as group_id from Chapter tt) cc where cc.group_id<=7 order by updateTime desc"];
*/
+ (NSArray *)query:(Class)model_class sql:(NSString *)sql;

/**
* 说明: 利用sqlite 函数进行查询

* @param model_class 要查询模型类
* @param sqliteFunc sqlite函数例如:(MAX(age),MIN(age),COUNT(*)....)
* @return 返回查询结果(如果结果条数 > 1返回Array , = 1返回单个值 , = 0返回nil)
* /// �example: [WHCSqlite query:[Person class] sqliteFunc:@"max(age)"];  /// 获取Person表的最大age值
* /// �example: [WHCSqlite query:[Person class] sqliteFunc:@"count(*)"];  /// 获取Person表的总记录条数
*/
+ (id)query:(Class)model_class func:(NSString *)func;

/**
* 说明: 利用sqlite 函数进行查询

* @param model_class 要查询模型类
* @param sqliteFunc sqlite函数例如:(MAX(age),MIN(age),COUNT(*)....)
* @param condition 其他查询条件例如:(where age > 20 order by age desc ....)
* @return 返回查询结果(如果结果条数 > 1返回Array , = 1返回单个值 , = 0返回nil)
* /// �example: [WHCSqlite query:[Person class] sqliteFunc:@"max(age)" condition:@"where name = '北京'"];  /// 获取Person表name=北京集合中的的最大age值
* /// �example: [WHCSqlite query:[Person class] sqliteFunc:@"count(*)" condition:@"where name = '北京'"];  /// 获取Person表name=北京集合中的总记录条数
*/
+ (id)query:(Class)model_class func:(NSString *)func condition:(NSString *)condition;

/**
* 说明: 更新本地模型对象
* @param model_object 模型对象
* @param where 查询条件(查询语法和SQL where 查询语法一样,where为空则更新所有)
*/

+ (BOOL)update:(id)model_object where:(NSString *)where;


/**
说明: 更新数据表字段

@param model_class 模型类
@param value 更新的值
@param where 更新条件
@return 是否成功
/// 更新Person表在age字段大于25岁是的name值为whc,age为100岁
/// �example: [WHCSqlite update:Person.self value:@"name = 'whc', age = 100" where:@"age > 25"];
*/
+ (BOOL)update:(Class)model_class value:(NSString *)value where:(NSString *)where;

/**
* 说明: 清空本地模型对象
* @param model_class 模型类
*/

+ (BOOL)clear:(Class)model_class;


/**
* 说明: 删除本地模型对象
* @param model_class 模型类
* @param where 查询条件(查询语法和SQL where 查询语法一样,where为空则删除所有)
*/

+ (BOOL)delete:(Class)model_class where:(NSString *)where;

/**
* 说明: 清空所有本地模型数据库
*/

+ (void)removeAllModel;

/**
* 说明: 清空指定本地模型数据库
* @param model_class 模型类
*/

+ (void)removeModel:(Class)model_class;

/**
* 说明: 返回本地模型数据库路径
* @param model_class 模型类
* @return 路径
*/

+ (NSString *)localPathWithModel:(Class)model_class;

/**
* 说明: 返回本地模型数据库版本号
* @param model_class 模型类
* @return 版本号
*/
+ (NSString *)versionWithModel:(Class)model_class;

Licenses

All source code is licensed under the MIT License.

whc_modelsqlitekit's People

Contributors

netyouli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

whc_modelsqlitekit's Issues

批量插入也是有点慢

利用inserts插入3000条简单的city数据就耗时2.383990秒,,,把三千条数据拆成100条插入一次,耗费的时间差不多,inserts最后还是跑到insert里边了,,跟自己调insert耗费时间差不多

两个小小问题

1,[local_model_name rangeOfString:version].location == NSNotFound,这里判断版本号的地方,是否有问题?比如1.0版本升级到1.0.1有多位字母表示的版本号,以及1.0版本升级到11.0版本时呢?直接字符串去比较版本号是否更合理?

2,数据库每次增删改查都是打开数据库,然后关闭,是否会有效率方面的影响?可否数据按ModelClass来建多张表到一个数据库里,打开一次,多个数据表公用一个数据库,而不是建立多个文件呢?

以上!

需求

能新增自定义数据库名字和和数据库路劲吗?请回复谢谢.

已解决!加密问题

WHC_ModelSqlite.m文件中:
561行:
if (![self setKey:is_update_psw ? old_psw : psw_key]) {
应该是:
if (![self setKey:is_update_psw ? psw_key : old_psw]) {

是否支持主键?

插入模型(更新模型),是否支持主键?如果主键相同则应该插入失败?

还是有业务调用是先query一次之后做判断,如果存在则update,不存在这insert?

几处改动(扩展)

1,定义的Model支持继承
`

  • (NSDictionary *)parserModelObjectFieldsWithModelClass:(Class)modelClass {
    if (modelClass == [NSObject class]) {
    //如果是NSObject,则意味着还没有定义字段
    return nil;
    }

    NSMutableDictionary * fields = [NSMutableDictionary dictionary];
    unsigned int property_count = 0;
    objc_property_t * propertys = class_copyPropertyList(modelClass, &property_count);

      }
    

    }
    free(propertys);

    if (modelClass.superclass) {
    NSDictionary *fieldSuper = [self parserModelObjectFieldsWithModelClass:modelClass.superclass];
    [fieldSuper enumerateKeysAndObjectsUsingBlock:^(id key,id obj,BOOL *stop){
    [fields setValue:obj forKey:key];
    }];
    }

    return fields;
    }
    `

2,对NSArray之类的数据也支持保存,
`
else if (class_type == [NSArray class] ||
class_type == [NSDictionary class] ||
class_type == [NSDate class] ||
class_type == [NSSet class] ||
class_type == [NSValue class]) {

            NSLog(@"检查模型类异常数据类型(不支持类型:%@)[自定义类型需要实现encodeWithCoder/initWithCoder",class_type);

            WHC_PropertyInfo * property_info = [[WHC_PropertyInfo alloc] initWithType:_Blob propertyName:property_name_string];

            [fields setObject:property_info forKey:property_name_string];

        }

`

3,对于定义的NSString类型,做强制判断,
case _String: { NSString * value = [model valueForKey:field]; id value = [model valueForKey:field]; if (value == nil) { value = @""; } if (![value isKindOfClass:[NSString class]]) { if ([value respondsToSelector:@selector(stringValue)]) { value = [value stringValue]; }else{ NSLog(@"value:%@ is not NSString!!!(save value as empty string)",value); break; } } iResult = sqlite3_bind_text(pp_stmt, index, [value UTF8String], -1, SQLITE_TRANSIENT); } break;

4,可自动扩展模型字段alter数据表,在创建数据表时,先判断是否已存在,然后自动重新解析字段
`//首先判断数据表是否已存在,是否需要更新字段
if ([self isTableExists:tableName]) {
//更新字段
NSLog(@"table:%@ has existed",tableName);

        bRes = [self alterTable:tableName fields:fields];
        break;
    }`

5,使用了FMDB/SQLCiper对数据库可加密处理;

6,在query数据之前,先判断是否存在文件,如果不存在,不自动创建数据表。

7,支持联合主键unionPrimaryKey,插入数据库时,先判断是否有主键,
`

  • (NSString *)primaryKeyWhereSQLForModel:(id)model{
    NSMutableString *sql = [NSMutableString stringWithString:@""];

    NSArray *primaryKeys = [self performFunc:kUnionPrimaryKeys forClass:[model class]];
    if ([primaryKeys count]>0) {
    for (NSString *key in primaryKeys) {
    id value = [model valueForKey:key];
    //TODO:value需要做类型判断以及转换
    if (value) {
    if (sql.length>0) {
    [sql appendString:@" and "];
    }

              [sql appendString:[NSString stringWithFormat:@"%@=\'%@\'",key,value]];
          }
      }
    

    }

    return sql;
    }
    `

以上主要改动的地方,多谢作者提供的该库;

能不能别把数据库路径写死

我如果用pod的话,希望你能开放一个数据库路径给我,就是不要把数据库路径写死,我有些数据不一定放到缓存的,谢谢。

关于update的问题

能不能根据条件update某一个字段的值,而不是全部清空?类似于sql语句
// BOOL result = [self.db executeUpdateWithFormat:@"update t_image set isUpload = %d where batch = %@",0,@"批次25"];

关于数据更新问题

超哥,我通过遍历数组一条一条更新数据库里的数据,但是发现数据错乱了,这个需要怎么处理。求超哥指导

whc_SqlitePath问题

使用很久了,今天看了一下库发现这个新功能,测试一下,感觉使用有点问题?
1.+ (NSString *)whc_SqlitePath方法是定义了一个绝对路径,WHC_ModelSqliteKit能否提供默认目录的API,返回xxxxx/Library/Caches/WHCSqlite/,然后去拼接?
猜测该协议使用场景一般只是为了区分多用户添加一个目录(Library/Caches/WHCSqlite/uid/),数据库存目录不用太分散,为了更适用应该是绝对路径,只是最好提供一个默认路径,使用者不需要去看原来数据库存放地址Library/Caches/WHCSqlite/uid/UserModelClass
2.使用whc_SqlitePath时,如果已有数据库的话,使用者需要处理迭代更新时,转移到指定目录。能否返回一个字典@{newPath:oldPath}?

  • (NSString *)databaseCacheDirectory:(Class)model_class的时候(这个库查找模型数据库目录的时候都用调用这个吧?)去处理移动,但是现在移动的时候有个问题(xxxxx/Library/Caches/WHCSqlite/Person_v1.0.0.sqlite)。这个方法改动的话,我无法找到原来的库路径,因为版本查询也调用。我想了一个方法,查找所有旧目录的文件,_v分割字符串?移动后名称还是原版本号,版本号逻辑版本号的协议方法去改。
    不知道这样对不对

关于插入数据

我准备采用你的开源库,存储聊天消息.
我这边采用的是分页,每次只能存储20条,假若有很多条的话,我如何能更好的处理

1.第一进入 我请求20条完数据后,变成Model存入数据库,第一次这样,没问题.
2.第二次进入, 我再进入页面,现在其中有15条是已经缓存好的,还有5条是未读的.

我假若要用您的开源:我目前想到的是
找到我和那个人的聊天记录,找到最先一条,找到最后一条的时间,若>于这个时间的话,我再继续存.否则只读,但是我觉得这样不怎么友好...

我可能没看源码看的太仔细, 请问下我这样如何能更加友好的将这套框架 应用到我的聊天消息系统里面?

SQLite 怎么并发读取数据?

超哥,我这边想问个 SQLite 的问题,我在测试 SQLite 并发读取,但测试结果发现:并发读取比单线程读取还耗时(单线程 5000 条耗时 12 秒左右,2500 条 6 秒左右,而两个线程各读取 2500 条,总共耗时 18 秒左右)。而安卓那边试了一下,发现是正常的。这可能是什么原因导致的?

以下是我的测试代码:

创建数据表并插入数据

fileprivate var dbPath: String!
fileprivate var db: FMDatabase?

dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/" + "tmp.db";
if let dbFh = FMDatabase(path: dbPath) {
    dbFh.open()
    if dbFh.tableExists("test") {
        db = dbFh
    } else if dbFh.executeUpdate("create table test (a text, b text, c integer, d double, e double)", withArgumentsIn: []) {
        db = dbFh
    }
}

transaction(count: 5000)

fileprivate func transaction(count: Int = 10) {

    guard count >= 0 else {
        return
    }

    guard let dbFh = db else {
        return
    }

    if !dbFh.open() {
        return
    }

    let image = UIImage(named: "image02")!
    let imgData = UIImageJPEGRepresentation(image, 1)!

    dbFh.beginTransaction()

    for index in 0..<count {
        if !dbFh.executeUpdate("insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)", withArgumentsIn: ["index\(index)", imgData, index, index, index]) {
            print("err:", dbFh.lastErrorMessage())
            break
        }
    }

    dbFh.commit()

    if !dbFh.close() {
        return
    }
}

并发读取:

var sdb :OpaquePointer? = nil
var sdb0 :OpaquePointer? = nil

func doubleThreadRead() {

    let group = DispatchGroup()

    let flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX

    group.enter()
    DispatchQueue.global().async {

        if sqlite3_open_v2(NSString(string: self.dbPath).fileSystemRepresentation, &self.sdb, flags, nil) == SQLITE_OK {
            print("open success")
        } else {
            print("open fail")
        }

        let startTime = CFAbsoluteTimeGetCurrent()

        var statement :OpaquePointer? = nil
        let sql = "select * from test limit 2500 offset 2500"
        sqlite3_prepare_v2(self.sdb!, (sql as NSString).utf8String, -1, &statement, nil)

        while sqlite3_step(statement) == SQLITE_ROW {
        }
        sqlite3_finalize(statement)

        sqlite3_close_v2(self.sdb)

        let endTime = CFAbsoluteTimeGetCurrent()

        print("db duration = ", endTime - startTime)

        group.leave()
    }

    group.enter()
    DispatchQueue.global().async {

        if sqlite3_open_v2(NSString(string: self.dbPath).fileSystemRepresentation, &self.sdb0, flags, nil) == SQLITE_OK {
            print("open success")
        } else {
            print("open fail")
        }

        let startTime = CFAbsoluteTimeGetCurrent()

        var statement :OpaquePointer? = nil
        let sql = "select * from test limit 2500"
        sqlite3_prepare_v2(self.sdb0!, (sql as NSString).utf8String, -1, &statement, nil)

        while sqlite3_step(statement) == SQLITE_ROW {
        }
        sqlite3_finalize(statement)

        sqlite3_close_v2(self.sdb0)

        let endTime = CFAbsoluteTimeGetCurrent()

        print("db0 duration = ", endTime - startTime)

        group.leave()
    }

    group.notify(queue: .main) {
        print("end")
    }
}

model的属性不设置的时候,不能insert。

最近有一个项目,因为返回数据的时候有些属性为空。
因此就只设置了A属性,没有设置B属性,使用insert创建的表里面没有数据。
需要怎么修改呢?感谢……

is there a way to insert or replace an object without adding it twice?

is there a way to insert or replace an object without adding it twice?
i don't want to add the same objects twice but i need to update them,
example : I persisted some objects from my web service into the database, all objects have an ID , when I update my web service data I don't want to add those objects twice but update them

多个表,如果表名相互有包含关系,会出错

commonLocalPathWithModel函数里面
这一句,假如两个表,Photo,Photoshop,查找出错
或者Photoshop 和shop也会出错
if ([obj rangeOfString:class_name].location != NSNotFound) {
希望这里能换个精确对比

model 实现 WHC_SqliteInfo 协议出现一些问题

1.表里会多出4个字段:hash、superclass、debugDesciption、description。
2.删除属性会崩溃。报错信息如下:
-[MSUser setHash:]: unrecognized selector sent to instance 0x60800002fde0

原因应该是 WHC_SqliteInfo 协议继承了 NSObject 协议,NSObject 协议里定义了 hash、superclass、debugDesciption、description 这些属性,不过都是 readonly 的,所以再用旧数据来给新 model 设置值的时候出现上面错误信息。让 WHC_SqliteInfo 协议不继承 NSObject 协议应该就可以了。

然后感谢作者开源,看到了一个不一样的数据库处理方案。

数据更新问题

  • (BOOL)update:(id)model_object where:(NSString *)where;

我想要更新这个模型还需要加上条件语句,而条件语句查询出来的可能不止一条,这样就会更新到不需要更新的数据了

谢谢开源,并请教两个问题

1、当模型的属性发生变化(如增加、减少、更名)时,是否有方法进行数据迁移(将变化之前已存储的数据直接通过某种规则迁移至新的模型结构中,迁移规则可借鉴 realm 直接已 block 交给业务方)?

2、是否需要业务方自己处理多线程资源竞争问题?

怎么设置主键呢

存储后更新,除了循环查找更新,有木有办法设置主键呢,存在即更新。

insert速度太慢

插入上千条数据就耗时10s左右,不明白为什么会这么慢,改用fmdb开启事务毫秒完成.
而且每个类都创建了一个数据库,感觉不太合理,创建表即可,为什么要创建数据库?

关于查询的问题

感觉查询没那么方便耶,感觉用的最多的就是查询了,查询可以多元化一点么?或者说支持原生的sql语句。因为可能涉及多表或者多模型的查询删除等问题
例如demo项目中:

NSArray * personArray = [WHC_ModelSqlite query:[Person class] where:@"name != '吴海超'"];
我想查询的是person的car的name 等于 撼路者的
NSArray * personArray = [WHC_ModelSqlite query:[Person class] where:@"person.car.name = '撼路者'"];

就是 查询父类模型的继承属性的值 或 或者父类子类同时满足的条件,删除同理。。
希望可以支持复杂的查询。。。谢谢哈,个人意见仅供参考哈

propertys释放问题

  • (id)autoNewSubmodelWithClass:(Class)model_class方法中propertys好像没有释放

关于密码的问题,我试过了,确实有问题

您的代码:试过,密码加密失败了,cypher已经正确引入了

+ (void)decryptionSqlite:(Class)model_class {
#ifdef SQLITE_HAS_CODEC
    NSString * psw_key = [self exceSelector:@selector(whc_SqlitePasswordKey) modelClass:model_class];
    if (psw_key && psw_key.length > 0) {
        // 取旧的密码
        NSString * old_psw = [self pswWithModel:model_class];  
        // 判断是否需要更新密码
        BOOL is_update_psw = (old_psw && ![old_psw isEqualToString:psw_key]);
        // 这句话bug:
        // 如果是第一次进来,sqlite数据库之前是没有密码的,old_psw是“”空字符串,设定一个空密码显然会失败,会报错,无法达到设定密码的目的
        // 如果是成功设定密码,第二次以及以后进来,逻辑是成立的,旧密码存在,打开数据库,然后重新设定密码,所以我修改在下一段
        if (![self setKey:is_update_psw ? old_psw  :  psw_key]) { 
            [self log:@"给数据库加密失败, 请引入SQLCipher库并配置SQLITE_HAS_CODEC或者pod 'WHC_ModelSqliteKit/SQLCipher'"];
        }else {
            // 重设密码
            if (is_update_psw) [self rekey:psw_key];       
            // 保存新密码到缓存     
            [self saveModel:model_class psw:psw_key];           
        }
    }
#endif
}

修改如下:

+ (void)decryptionSqlite:(Class)model_class {
#ifdef SQLITE_HAS_CODEC
    NSString * psw_key = [self exceSelector:@selector(whc_SqlitePasswordKey) modelClass:model_class];
    if (psw_key && psw_key.length > 0) {
        NSString * old_psw = [self pswWithModel:model_class];// 取旧的密码
        BOOL is_update_psw = (old_psw && [old_psw length] > 0 && ![old_psw isEqualToString:psw_key]);
        if (![self setKey:is_update_psw ? old_psw : psw_key]) { // 获取密码先 - 也是打开加密数据库的方法
            [self log:@"给数据库加密失败, 请引入SQLCipher库并配置SQLITE_HAS_CODEC或者pod 'WHC_ModelSqliteKit/SQLCipher'"];
        }else {
            if (is_update_psw) [self rekey:psw_key];            // 重设密码
            [self saveModel:model_class psw:psw_key];           // 保存新密码
        }
    }
#endif
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.