这里只是提到了一些基础是用法。深度用法,可以前往官网学习。 关于WCDB的背景和优缺点,这里也不做介绍,大家可以自行百度。
类字段绑定(ORM)
在WCDB内,ORM(Object Relational Mapping)是指
将一个ObjC的类,映射到数据库的表和索引;
将类的property,映射到数据库表的字段;
这一过程。通过ORM,可以达到直接通过Object进行数据库操作,省去拼装过程的目的。
WCDB通过内建的宏来实现ORM的功能。
首先创建一个model:
.h
#import "DetailModel.h"
@interface Draft1 : NSObject
@property int localID;
@property(retain) NSString *content;
@property(retain) NSString *title;
@property(retain) NSDate *createTime;
@property(retain) NSDate *modifiedTime;
@property(assign) int unused;
@property (nonatomic, strong) DetailModel *model;
@end
.mm
#import
@implementation Draft1
WCDB_IMPLEMENTATION(Draft1)
WCDB_SYNTHESIZE(Draft1, localID)
WCDB_SYNTHESIZE(Draft1, content)
WCDB_SYNTHESIZE(Draft1, createTime)
WCDB_SYNTHESIZE(Draft1, modifiedTime)
WCDB_SYNTHESIZE(Draft1, model)
WCDB_SYNTHESIZE(Draft1, title)
//主键
WCDB_PRIMARY(Draft1, localID)
WCDB_INDEX(Draft1, "_index", createTime)
@end
由于WCDB是结合c++写的,引用#import
创建对应model的分类
.h
#import
NS_ASSUME_NONNULL_BEGIN
@interface Draft1 (wcdb)
WCDB_PROPERTY(localID)
WCDB_PROPERTY(content)
WCDB_PROPERTY(title)
WCDB_PROPERTY(createTime)
WCDB_PROPERTY(modifiedTime)
WCDB_PROPERTY(model)
@end
将一个已有的ObjC类进行ORM绑定的过程如下:
定义该类遵循WCTTableCoding协议。可以在类声明上定义,也可以通过文件模版在category内定义。
使用WCDB_PROPERTY宏在头文件声明需要绑定到数据库表的字段。
使用WCDB_IMPLEMENTATIO宏在类文件定义绑定到数据库表的类。
使用WCDB_SYNTHESIZE宏在类文件定义需要绑定到数据库表的字段。
简单几行代码,就完成了将类和需要的字段绑定到数据库表的过程。这三个宏在名称和使用习惯上,也都和定义一个ObjC类相似,以此便于记忆。
除此之外,WCDB还提供了许多可选的宏,用于定义数据库索引、约束等,如:
WCDB_PRIMARY用于定义主键
WCDB_INDEX用于定义索引
WCDB_UNIQUE用于定义唯一约束
WCDB_NOT_NULL用于定义非空约束
具体用法
在我们的项目中,定义好的接口(SEEDDBManagerProtocol) 可以满足一般场景的增删改查。
#import
@protocol SEEDDBManagerProtocol
@required
//便利构造器
+ (instancetype)shareManager;
#pragma mark -- create table
/// 创建具体的表
/// @param tableName 表名
/// @param modelClass 对应的model的类
- (BOOL)createTableWithName:(NSString *)tableName
modelClass:(Class)modelClass;
@optional
#pragma mark -- insert
/// 在某个已知的表里,插入新单个数据
/// @param message 需要插入的数据
- (BOOL)insertData:(WCTObject *)message;
/// 在某个已知的表里,插入(已经存在该数据,就更新)新单个数据
/// @param message 需要插入的数据
- (BOOL)insertOrReplaceObject:(WCTObject *)message;
/// 在某个表里,插入单个数据
/// @param message 需要插入的数据
/// @param tableName 表名
/// @param modelClass 对应model的类名
- (BOOL)insertData:(WCTObject *)message
withTableName:(NSString *)tableName
modelClass:(Class)modelClass;
/// 在某个表里,插入(已经存在该数据,就更新)单个数据
/// @param message 需要插入的数据
/// @param tableName 表名
/// @param modelClass 对应model的类名
- (BOOL)insertOrReplaceObject:(WCTObject *)message
withTableName:(NSString *)tableName
modelClass:(Class)modelClass;
#pragma mark -- update
/// 在某个已知的表里,更新草稿数据
/// @param message 需要更新的数据
- (BOOL)updateData:(WCTObject *)message;
/// 在某个表里,更新单个数据
/// @param tableName 表名
/// @param property 需要更新的属性
/// @param value 对应的值
- (BOOL)updateAllRowsInTable:(NSString *)tableName
onProperty:(const WCTProperty &)property
withValue:(WCTValue *)value;;
#pragma mark -- select
/// 在某个已知的表里,根据条件获取某个单独的草稿数据
/// @param where 条件
- (WCTObject *)selectData:(const WCTCondition &)where;
/// 在某个表里,根据条件获取某个单独的草稿数据
/// @param where 条件
/// @param tableName 表名
/// @param modelClass 对应model的类
- (WCTObject *)selectData:(const WCTCondition &)where
withTableName:(NSString *)tableName
modelClass:(Class)modelClass;
#pragma mark -- delete
/// 在某个已知的表里,删除某个数据
/// @param where 条件
- (BOOL)delegateData:(const WCTCondition &)where;
/// 在某个已知的表里,删除某个数据
/// @param where 条件
/// @param tableName 表名
/// @param modelClass 对应model的类
- (BOOL)delegateDataWithWhere:(const WCTCondition &)where
withTableName:(NSString *)tableName
modelClass:(Class)modelClass;
/**
未完待续......
*/
@end
创建数据库
#define kDataBaseFileName @"SEEDDB.sqlite"
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static SEEDDBManager *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_instance == nil) {
_instance = [super allocWithZone:zone];
[_instance creatDatabase];
}
});
return _instance;
}
+ (instancetype)shareManager {
return [[self alloc] init];
}
//创建数据库
- (BOOL)creatDatabase{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbPath = [documentPath stringByAppendingString:kDataBaseFileName];
self.database = [[WCTDatabase alloc] initWithPath:dbPath];
self.database.tag = 0;
if ([self.database canOpen]) {
NSLog(@"创建数据库成功");
}else{
NSLog(@"创建数据库失败");
return NO;
}
return YES;
}
创建具体的表
//创建具体的表
- (BOOL) createTableWithName:(NSString *)tableName modelClass:(Class)modelClass{
//创建表 注:该接口使用的是IF NOT EXISTS的SQL,因此可以用重复调用。不需要在每次调用前判断表或索引是否已经存在。
BOOL result = [self.database createTableAndIndexesOfName:tableName withClass:modelClass];
if (!result) {
NSLog(@"创建表失败");
return NO;
}
NSLog(@"创建表成功");
return YES;
}
创建SEEDDBManager 的分类,来跟具体业务绑定。
#define kTable_Name @"TableName"
@implementation SEEDDBManager (businessOne)
/// 在某个已知的表里,插入(已经存在该数据,就更新)新单个数据
/// @param message 需要插入的数据
- (BOOL)insertOrReplaceObject:(Draft1 *)message{
BOOL result = [self.database insertOrReplaceObject:message into:kTable_Name];
//关闭数据库,_database如果能自己释放的话,会自动关闭,就不用手动调用关闭了
[self.database close];
if (!result) {
NSLog(@"插入失败");
return NO;
}else{
NSLog(@"插入成功");
return YES;
}
}
/// 在某个已知的表里,根据条件获取某个单独的草稿数据
/// @param where 条件
- (WCTObject *)selectData:(const WCTCondition &)where{
WCTTable *table = [self.database getTableOfName:kTable_Name withClass:Draft1.class];
WCTObject *objc = [ table getOneObjectWhere:where];
return objc;
}
/// 在某个已知的表里,删除某个数据
/// @param message 需要插入的数据
- (BOOL)delegateData:(Draft1 *)message{
//删除
//DELETE FROM message WHERE localID>0;
BOOL result = [self.database deleteObjectsFromTable:kTable_Name
where:Draft1.localID == message.localID];
return result;
}
这样可以使用全局统一的SEEDDBManager单利对象来调用数据库方法。 具体的业务代码则由各自SEEDDBManager的分类管理。
关于model的嵌套
在业务场景中,很容易遇到在Draft1模型的内部包含有一个其他的model。
不做任何处理的话,是没法正常使用的。
WCDB提供了一些具体的类型和方法如下:
需要在内部嵌套的model类,做一些处理。 需要实现
- (id)columnTypeForWCDB:
- (instancetype)unarchiveWithWCTValue:(WCTValue *)value;
- (id)archivedWCTValue;
这三个方法。
创建DetailModel
.h
#import
@interface DetailModel : NSObject
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *content;
WCDB_PROPERTY(title)
WCDB_PROPERTY(content)
@end
. mm
@implementation DetailModel
WCDB_IMPLEMENTATION(DetailModel)
WCDB_SYNTHESIZE(DetailModel, title)
WCDB_SYNTHESIZE(DetailModel, content)
- (id)archivedWCTValue {
return [NSKeyedArchiver archivedDataWithRootObject:self];;
}
+ (WCTColumnType)columnTypeForWCDB {
return WCTColumnTypeBinary;
}
+ (instancetype)unarchiveWithWCTValue:(WCTValue *)value {
if (value) {
@try {
DetailModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:value];
return model;
}
@catch (NSException *exception) {
NSLog(@"exception:%@",[exception description]);
}
}
return nil;
}
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int outCount = 0;
Ivar *ivars = class_copyIvarList([self class], &outCount);
for (unsigned int i =0; i
这样就可以model嵌套了。