LKDBHelper 、FMDB的简介。
在项目的开发过程中,我们大部分时候都需要对数据做一个持久化的操作,最典型的就是 IM 类型的项目,消息都要做保存。 还有就是像个人重要的信息,一般也会存本地,和服务器做一个同步处理。 数据的持久化可以有多种方法。 这里简单讲讲 FMDB 、以及 基于FMDB 二次封装,提供简单接口的 LKDBHelper 第三方库的使用。
LKDBHelper Git 地址 : https://github.com/li6185377/LKDBHelper-SQLite-ORM
部分接口整合,代码。
只要是继承 NSObject 的类,都可以使用 LKDBHelper 的接口进行对 Model 的一个增删改查。 (可以创建一个 BaseModel 的基类,然后其他Model 都继承于此,这样方法统一管理 Model)
直接上代码 :
1.先创建一个简单的工程 ,再创建一个 LKModelTest 类。 (带上各种类型的属性)
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface LKModelTest : NSObject
@property (nonatomic, assign) int ID;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, assign) NSUInteger age;
@property (nonatomic, assign) BOOL isMan;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSData *data;
@property (nonatomic, assign) CGFloat floatValue;
@property (nonatomic, assign) CGRect frame;
@property (nonatomic, assign) CGPoint point;
@property (nonatomic, assign) NSRange *range;
@end
.m 文件这几个方法需要实现下。
#import "LKModelTest.h"
@implementation LKModelTest
//重载、初始化单例、使用的LKDBHelper
+ (LKDBHelper *)getUsingLKDBHelper {
static LKDBHelper* db;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//DB 路径
NSString* DBPath = [NSHomeDirectory() stringByAppendingPathComponent:@"DB/DBTest.db"];
NSLog(@"%@", DBPath);
db = [[LKDBHelper alloc] initWithDBPath:DBPath];
});
return db;
}
//在类 初始化的时候
+ (void)initialize {
//如果getTableMapping 返回 nil, 会取全部属性, 如果有不想要的属性,可以使用
// [self removePropertyWithColumnName:@"age"];
// [self removePropertyWithColumnNameArray:@[@"age", @"name"]];
//修改列名
// [self setTableColumnName:@"MyAge" bindingPropertyName:@"age"];
//手动设置关联外键变量名
// [self setUserCalculateForCN:@""];
}
+ (void)dbDidAlterTable:(LKDBHelper *)helper tableName:(NSString *)tableName addColumns:(NSArray *)columns {
LKErrorLog(@"your know %@",columns);
}
// 将要插入数据库
+ (BOOL)dbWillInsert:(NSObject *)entity {
LKErrorLog(@"将要插入 : %@",NSStringFromClass(self));
return YES;
}
//已经插入数据库
+ (void)dbDidInserted:(NSObject *)entity result:(BOOL)result {
LKErrorLog(@"已经插入 : %@",NSStringFromClass(self));
}
+ (BOOL)dbWillUpdate:(NSObject*)entity {
LKErrorLog(@"将要更新 : %@",NSStringFromClass(self));
return YES;
}
+ (void)dbDidUpdated:(NSObject*)entity result:(BOOL)result {
LKErrorLog(@"已经更新 : %@",NSStringFromClass(self));
}
+ (BOOL)dbWillDelete:(NSObject*)entity {
LKErrorLog(@"将要删除 : %@",NSStringFromClass(self));
return YES;
}
+ (void)dbDidDeleted:(NSObject*)entity result:(BOOL)result {
LKErrorLog(@"已经删除 : %@",NSStringFromClass(self));
}
//手动or自动 绑定sql列
+ (NSDictionary *)getTableMapping {
//返回nil 就是自动绑定所有列名
return nil;
// return @{@"age":@"Myage"};
}
//主键
+ (NSString *)getPrimaryKey {
return @"ID";
}
///复合主键 这个优先级最高
//+(NSArray *)getPrimaryKeyUnionArray {
// return @[@"name",@"age"];
//}
//表名
+ (NSString *)getTableName {
return NSStringFromClass(self);
}
//是否将父实体类的属性也映射到sqlite库表
+ (BOOL)isContainParent {
return YES;
}
@end
+ (NSDictionary *)getTableMapping;
来进行移除,也可以手动修改个别你需要更改列名的列:
[self setTableColumnName:@"新列名" bindingPropertyName:@"原列名"];
如果你有两张或者以上的表互相关联,需要设置外键的话,可以在 initialize 方法中调这个方法:
[self setUserCalculateForCN:@"关联的表,在当前属性中创建的变量名"];
这个参数什么意思? 比如: 有个A 类 和 B类 关联。
那么在 B 类的属性中,就会创建一个这样的属性
@property (nonatomic, strong) A *thisAObj;
则在 B 的这个方法里就要这么写:
[self setUserCalculateForCN:@"thisAObj"];
+ (NSString *)getTableName {
return NSStringFromClass(self);
}
表也需要个表名, 所以这个方法 默认将 类名 作为 表名。
//主键
+ (NSString *)getPrimaryKey {
return @"ID";
}
///复合主键 这个优先级最高
//+(NSArray *)getPrimaryKeyUnionArray {
// return @[@"name",@"age"];
//}
一般情况下,你的Model数据也都会有一个唯一的值,这个值就可以来作为 主键, 主键的用途,后面再插入数据,或者删除,更改 都可以用来快速定位到某条数据条件,主键不能为空, 也不可能重复,如果你 保存某条 数据进去,但是主键对应的数据已经存在,则会覆盖那条数据。 复合主键,相当于多个条件一起约束一条数据,这种情况适用于当一个主键不能满足的时候。
//是否将父实体类的属性也映射到sqlite库表
+ (BOOL)isContainParent {
return YES;
}
这个方法是设置 是否需要将父类的属性 也一起绑定在表中。
Model 的方法大致就这样设置 基本上就行了。
接下来在 ViewController.m 中,开始使用数据库存储。
///获取 LKTest 类使用的 LKDBHelper
LKDBHelper *globalHelper = [LKModelTest getUsingLKDBHelper];
[globalHelper dropAllTable];
//清空表数据 clear table data
[LKDBHelper clearTableData:[LKModelTest class]];
LKModelTest *model = [LKModelTest new];
model.name = @"张三1";
model.nickName = @"马蓉婊子";
model.isMan = YES;
model.image = [UIImage imageNamed:@"imageValue"];
model.color = [UIColor blueColor];
model.date = [NSDate new];
model.data = [@"yutianlong9306" dataUsingEncoding:NSUTF8StringEncoding];
model.floatValue = 3.1415926f;
model.frame = CGRectMake(0, 0, 100, 100);
model.point = CGPointMake(200, 200);
//插入5条数据
for (int i = 1; i < 6 ; i++) {
model.ID = i;
model.age = 20 + i;
[model saveToDB];
}
先插入 5 条 Model 数据。
下面的代码, 就是各种SQL 条件组合查询语句 : (最后会附上Demo 下载地址)
sleep(2);
NSMutableArray *searchResultArray = nil;
//同步搜索 执行sql语句 把结果再变成对象 **************查询操作*******
// sql 1 查找表所有记录
NSString *sql1 = @"select * from LKModelTest";
searchResultArray = [globalHelper searchWithSQL:sql1 toClass:[LKModelTest class]];
addText(@"********** 查找表所有记录 \n");
for (id obj in searchResultArray) {
addText(@"%@", [obj printAllPropertys]);
}
// sql 2 按条件查询 (多条件)
NSString *sql2 = @"select * from LKModelTest where name = '张三1' and age = 22";
searchResultArray = [globalHelper search:[LKModelTest class] withSQL:sql2];
addText(@"********** 按条件查询 (多条件) \n");
for (id obj in searchResultArray) {
addText(@"%@", [obj printAllPropertys]);
}
// sql 3 条件使用动态参数 ? ,即接口传进来的,search使用如下接口
NSString *sql3 = @"select * from LKModelTest where name = ?";
NSString *name = @"张三1"; //假设这个 name 是接口传进来的 , 就可以有以下的写法
searchResultArray = [globalHelper search:[LKModelTest class] withSQL:sql3, name];
addText(@"********** 条件使用动态参数 ? \n");
for (id obj in searchResultArray) {
addText(@"%@", [obj printAllPropertys]);
}
//*********************查询操作************************************
//使用对象对进查询操作 orderBy 可以指定某个列倒叙查询 offset是跳过多少行 count是查询多少条(为0查询所有)
// 无条件查询 10 条
searchResultArray = [LKModelTest searchWithWhere:nil orderBy:nil offset:0 count:10];
// 无条件查询 某个列的值
searchResultArray = [LKModelTest searchColumn:@"age" where:nil orderBy:nil offset:0 count:10];
// 根据一个自增长的列,倒叙查询 最新10条数据 (自增长的列可以是 自定义属性ID,也可以是自带的 rowid)
searchResultArray = [LKModelTest searchWithWhere:nil orderBy:@"ID desc" offset:0 count:10];
// 根据 and 条件 查询所有数据
NSString *conditions = @"age = 23 and name = '张三1'";
searchResultArray = [LKModelTest searchWithWhere:conditions orderBy:nil offset:0 count:0];
// 根据 字典条件,查询所有数据
NSDictionary *conditions1 = @{@"age" : @23, @"name" : @"张三1"};
searchResultArray = [LKModelTest searchWithWhere:conditions1 orderBy:nil offset:0 count:0];
// 根据 or 条件,查询所有数据
NSString *conditions2 = @"age = 23 or ID = 5";
searchResultArray = [LKModelTest searchWithWhere:conditions2 orderBy:nil offset:0 count:0];
// 根据 in 条件,查询所有数据
NSString *conditions3 = @"age in (23, 24)";
searchResultArray = [LKModelTest searchWithWhere:conditions3 orderBy:nil offset:0 count:0];
// 根据 字典 in 条件,查询所有数据
NSDictionary *conditions4 = @{@"age" : @[@23, @24]};
searchResultArray = [LKModelTest searchWithWhere:conditions4 orderBy:nil offset:0 count:0];
// 查询符合条件的数据有多少条
NSString *conditions5 = @"age = 23 and name = '张三1'";
NSInteger rowCount = [LKModelTest rowCountWithWhere:conditions5];
NSLog(@"%ld", rowCount);
for (id obj in searchResultArray) {
[obj printAllPropertys];
}
//*********************更新操作*********************************
// 带条件更新 , 一般来说,这种方式更新不需要where条件,因为会根据主键更新
model.name = @"马蓉 婊子";
BOOL isUpdate1 = [globalHelper updateToDB:model where:nil];
// 更新 访问表名 更新内容跟条件进行更新
BOOL isUpdate2 = [globalHelper updateToDBWithTableName:@"LKModelTest" set:@"name = '马蓉小婊砸'" where:@"age = 22"];
// 根据 实类、条件进行更新
BOOL isUpdate3 = [globalHelper updateToDB:[LKModelTest class] set:@"name = '马蓉小畜生'" where:@"age = 23"];
//*********************删除操作*********************************
// 根据model 删除 ,两种方式
BOOL isDelete1 = [globalHelper deleteToDB:model];
//or
[model deleteToDB];
// 根据条件,删除多条数据
BOOL isDelete2 = [globalHelper deleteWithClass:[LKModelTest class] where:@"age >= 22 and age <= 24"];
Demo 会把部分 sql 执行接口打印在屏幕上,如果童鞋们 有需要打印其他信息,调用 addText(@""); 方法即可。
打印信息 :
![](https://img-my.csdn.net/uploads/201608/19/1471577521_3876.gif)
Demo 下载地址: