WCDB学习笔记S1 - ORM

2,480 阅读5分钟

安装

Cocoapods

  1. 在podfile文件中对应的target下添加pod 'WCDB',执行pod install
  2. 在需要引用WCDB的文件头添加#import <WCDB/WCDB.h>。由于WCDB是基于Object-C++的,所以引用WCDB的文件后缀要改成.mm

类字段绑定(ORM)

概述

ORM主要是指将Objective-C的类映射到数据库表和索引,将类的property映射到数据库表中的字段。

绑定过程:

  • 遵守WCTTableCoding协议
  • 使用WCDB_PROPERTY宏定义在头文件声明需要绑定到数据库表的字段。
  • 使用WCDB_IMPLEMENTATION宏定义在实现文件中定义需要绑定到数据库的类。
  • 使用WCDB_SYNTHESIZE宏定义在实现文件中定义需要绑定到数据库表的字段。

ORM宏

字段宏

  • WCDB_SYNTHESIZE(className, propertyName),直接使用propertyName作为数据库表字段名。
  • WCDB_SYNTHESIZE_COLUMN(className, propertyName, columnName),支持自定义字段名。使用columnName作为数据库表的字段名,以替换propertyName
  • WCDB_SYNTHESIZE_DEFAULT(className, propertyName, defaultValue),设置默认值。defaultValue为默认值。可以为任意的C类型或NSString,NSData,NSNumber,NSNull
  • WCDB_SYNTHESIZE_COLUMN_DEFAULT(className, propertyName, columnName, defaultValue),为上两种情况的组合。

#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface UserInfoModel : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *userId;
@property (nonatomic, copy) NSString *nick;
@property (nonatomic, assign) double height;

@end

NS_ASSUME_NONNULL_END



#import "UserInfoModel.h"
#import <WCDB/WCDB.h>

@implementation UserInfoModel

WCDB_IMPLEMENTATION(UserInfoModel)		// 将UserInfoModel类绑定到数据库
WCDB_SYNTHESIZE(UserInfoModel, userId)	// userId作为数据库表字段名
WCDB_SYNTHESIZE(UserInfoModel, name)		// name作为数据库表字段名
WCDB_SYNTHESIZE_COLUMN(UserInfoModel, age, "replaceAge")	// 使用replaceAge作为数据库表字段名
WCDB_SYNTHESIZE_DEFAULT(UserInfoModel, nick, @"default nick")	// 使用nick作为数据库表字段名,并且默认值为default nick
WCDB_SYNTHESIZE_COLUMN_DEFAULT(UserInfoModel, height, "replaceHeight", 195)	// 使用replaceHeight作为数据库表字段名,并且默认值为195

@end

创建数据库

完成类的定义后,只需要调用createTableAndIndexesOfName:withClass:即可完成数据库表的创建。

WCTDatabase *database = [[WCTDatabase alloc] initWithPath:mngr.dbPath];

BOOL ret = [database createTableAndIndexesOfName:TABLE_USER withClass:UserInfoModel.class];

数据库表结构如下:

约束宏

约束宏包括字段约束和表约束

字段约束
  • 主键约束

    WCDB_PRIMARY(className, propertyName)定义主键,直接使用propertyName作为数据库表的主键。
    WCDB_PRIMARY_ASC(className, propertyName),主键升序。
    WCDB_PRIMARY_DESC(className, propertyName),主键降序。
    WCDB_PRIMARY_AUTO_INCREMENT(className, propertyName),定义主键自增。 WCDB_PRIMARY_ASC_AUTO_INCREMENT(className, propertyName),主键自增和升序的组合。

注意:
实现主键自增时,需要在插入数据之前设置关联类对象的model.isAutoIncrement = YES;

  • 非空约束

    WCDB_NOT_NULL(className, propertyName),当该字段插入数据为空时,数据库会报错。

  • 唯一约束

    WCDB_UNIQUE(className, propertyName),当该字段插入数据与其他行冲突时,数据库会报错。

表约束
  • 多主键约束

    多主键约束以WCDB_MULTI_PRIMARY开头,定义了数据库的多主键,支持自定义每个主键的排序方式。

    WCDB_MULTI_PRIMARY(className, constraintName, propertyName),多个主键通过constraintName匹配
    WCDB_MULTI_PRIMARY_ASC(className, constraintName, propertyName),定义多主键,propertyName主键升序。
    WCDB_MULTI_PRIMARY_DESC(className, constraintName, propertyName),定义多主键,propertyName主键降序。

    /**
     主键为userId和age,age主键升序
     */
    WCDB_MULTI_PRIMARY(UserInfoModel, "_oxfff", userId)
    WCDB_MULTI_PRIMARY_ASC(UserInfoModel, "_oxfff", age)
    
  • 多主键唯一约束

    多字段唯一约束以WCDB_MULTI_UNIQUE开头,定义了数据库的多字段组合唯一,支持自定义每个字段的排序方式。
    WCDB_MULTI_UNIQUE(className, constraintName, propertyName),多字段唯一约束。
    WCDB_MULTI_UNIQUE_ASC(className, constraintName, propertyName),多字段唯一约束,propertyName对应的字段升序。 WCDB_MULTI_UNIQUE_DESC(className, constraintName, propertyName),多字段唯一约束,propertyName对应的字段降序。

    /**
     主键为userId和age唯一,age对应的字段升序
     */
    WCDB_MULTI_UNIQUE(UserInfoModel, "_oxfff", userId)
    WCDB_MULTI_UNIQUE_ASC(UserInfoModel, "_oxfff", age)
    

类型

SQLite数据库支持整型,浮点数,字符串,二进制数据等类型。WCDB的ORM会自动识别属性的类型并映射到合适的数据库类型。

C类型 数据库类型
整型 整型(INTEGER)
枚举型 整型(INTEGER)
浮点数 浮点型(REAL)
字符串(const char *的C字符串类型) 字符串(TEXT)
Object-C类型 数据库类型
NSDate 整型(INTEGER)
NSNumber 浮点型(REAL)
NSString 字符串(TEXT)
其他所有符合NSCoding协议的NSObject子类 二进制(BLOB)

关联的类属性中引用别的类时,需要引用到的类遵守并实现NSCoding协议。在数据库中字段类型为二进制类型。

自定义类型

WCDB支持自定义绑定类型。类只需要实现WCTColumnCoding协议,就可以实现绑定。

@protocol WCTColumnCoding
@required
+ (instancetype)unarchiveWithWCTValue:(WCTValue *)value; //value could be nil
- (id /* WCTValue* */)archivedWCTValue;                  //value could be nil
+ (WCTColumnType)columnTypeForWCDB;
@end

可以使用WCDB官方提供的Xcode文件模板创建,也可以自行实现。

@interface Dog : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end   

#import "Dog.h"

#import <WCDB/WCDB.h>
#import <YYModel/YYModel.h>

@interface Dog()<WCTColumnCoding>

@end

@implementation Dog

- (id)archivedWCTValue {
    
    return [self yy_modelToJSONString];
}

+ (WCTColumnType)columnTypeForWCDB {
    
    return WCTColumnTypeString;	// 类型为String
}

+ (instancetype)unarchiveWithWCTValue:(WCTValue *)value {
    
    return value ? [Dog yy_modelWithJSON:value] : nil;
}

WCTColumnType

typedef NS_ENUM(int, WCTColumnType) {
    WCTColumnTypeInteger32 = (WCTColumnType) WCDB::ColumnType::Integer32,
    WCTColumnTypeInteger64 = (WCTColumnType) WCDB::ColumnType::Integer64,
    WCTColumnTypeDouble = (WCTColumnType) WCDB::ColumnType::Float,
    WCTColumnTypeString = (WCTColumnType) WCDB::ColumnType::Text,
    WCTColumnTypeBinary = (WCTColumnType) WCDB::ColumnType::BLOB,
    WCTColumnTypeNil = (WCTColumnType) WCDB::ColumnType::Null,
};

WCDB内置对部分常用Object-C类型(如NSData,NSDate等)的支持。如果想自己定义基本类型,可以将内置的绑定关闭。关闭方法为:删除工程文件的Build Settings->Preprocessor Macros下各个schemeWCDB_BUILTIN_COLUMN_CODING宏。

修改字段

SQLite支持增加,不支持删除、重命名字段。

增加字段

只需要在定义处添加WCDB_SYNTHESIZE(className, propertyName),然后重新执行createTableAndIndexesOfName:withClass:即可。

删除字段

只需将要删除的字段的定义删除即可。

这里只是忽略这个字段,数据库表中旧的数据依然会存在。

重命名字段

使用WCDB_SYNTHESIZE_COLUMN(className, propertyName, columnName) 重新映射。

这里相当于在数据库表中添加一个新的字段。

其他注意事项

修改类的属性名时,需要重新映射。