GYDataCenter 是为喜欢直接使用 SQLite 的人提供 Core Data 的一个替代方案。
GYDataCenter 是基于 FMDB 开发的。它提供了面向对象的接口,同时仍保留了使用原始 SQL 的灵活性。如果您希望使用 Core Data 一样的便利性并增加对实现、性能、查询和索引的控制,GYDataCenter 是一个不错的选择。
pod 'GYDataCenter'
1) 正常定义您的模型类,除了让它们成为 GYModelObject 的子类。
@interface Employee : GYModelObject
@property (nonatomic, readonly, assign) NSInteger employeeId;
@property (nonatomic, readonly, strong) NSString *name;
@property (nonatomic, readonly, strong) NSDate *dateOfBirth;
@property (nonatomic, readonly, strong) Department *department;
@end
2) 实现以下协议方法。告诉 GYDataCenter 数据库名称、用于模型的表名称、您想设为主键的属性以及您想持久化的属性。
+ (NSString *)dbName {
return @"GYDataCenterTests";
}
+ (NSString *)tableName {
return @"Employee";
}
+ (NSString *)primaryKey {
return @"employeeId";
}
+ (NSArray *)persistentProperties {
static NSArray *properties = nil;
if (!properties) {
properties = @[
@"employeeId",
@"name",
@"dateOfBirth",
@"department"
];
});
return properties;
}
3) 保存和查询模型对象,如下所示。
Employee *employee = ...
[employee save];
employee = [Employee objectForId:@1];
NSArray *employees = [Employee objectsWhere:@"WHERE employeeId < ? ORDER BY employeeId"
arguments:@[ @10 ]];
如图所示,一旦正确定义了模型类,您就可以保存和查询模型对象。您不需要自己创建数据库文件或表。GYDataCenter 会自动为您完成这些工作。
此外,一旦创建了一个表,如果添加了更多的持久化属性,GYDataCenter 将为您更新表架构,添加新的列。然而,GYDataCenter 不能 删除或重命名现有的列。如果您计划这样做,您需要创建一个新的表并自己迁移数据。
索引 也由 GYDataCenter 维护。GYDataCenter 能够在您实现并修改以下协议方法时自动创建和删除索引:
+ (NSArray *)indices {
return @[
@[ @"dateOfBirth" ],
@[ @"department", @"name" ]
];
}
问题:GYDataCenter 在什么情况下创建或更新表架构以及如何操作?
每次应用重新启动后,对于给定的模型,GYDataCenter 会在您第一次使用 GYDataCenter 的 API 操作该模型的数据时,检查是否需要创建或更新表以及索引。GYDataCenter 使用运行时 API 查询每个属性的属性类型,并为每个属性指定合适的列类型。
GYDataCenter 使用 SQL 的 where 子句来过滤数据库中的记录。您无需学习一套全新的谓词来使用 GYDataCenter,同时这样做也保持了 SQL 的灵活性。
NSArray *employees = [Employee objectsWhere:@"WHERE employeeId < ? ORDER BY employeeId"
arguments:@[ @10 ]];
实际上,您可以在 where 子句的位置使用任何有效的 SQL 子句。
NSArray *employees = [Employee objectsWhere:@"ORDER BY employeeId"
arguments:nil];
NSArray *employees = [Employee objectsWhere:@"LIMIT 1"
arguments:nil];
甚至是嵌套查询。
NSArray *employees = [Employee objectsWhere:@"WHERE department in (SELECT departmentId from department WHERE name = ?)"
arguments:@[ @"Human Resource" ]];
强烈建议将值绑定到 where 子句而非内联它们。这样做不仅防止 SQL 注入,还增加了重复使用 SQLite 语句的机会。因此,始终使用 '?' 作为值占位符并在 arguments
参数中传递它们。
以下属性类型目前受到支持
int
unsigned
short
long
unsigned long
long long
unsigned long long
bool, BOOL
float
double
char
NSInteger, NSUInteger
NSString, NSMutableString
NSDate
NSData, NSMutableData
Classes that conforms to @protocol NSCoding
Classes that conforms to @protocol GYTransformableProtocol
Subclasses of GYModelObject
GYDataCenter 支持将模型类作为持久属性的类型。例如,模型 Employee 有一个名为 department 的属性,其类型为模型 Department。这被称为 关系。GYDataCenter 会在 Emplyee 表中创建一个列来存储 Department 的主键值。关系属性在实现中**必须**声明为动态。
@dynamic department;
当保存 Employee 对象时,GYDataCenter 将**不会**在 Department 表中为 department 属性插入新的记录。它只会在新员工记录中存储 department 的主键值。因此,如果您想保存部门,需要显式地这样做。
[employee save];
[employee.department save];
当查询 Employee 对象时,GYDataCenter 将不会为 department 属性检索整个 Department 对象。它将使用仅有一个有效主键的占位符对象。一旦您访问 department 属性,它将被完全实现。这称为**故障**,并由 GYDataCenter 自动完成。故障限制了对象图的大小,减少了应用程序消耗的内存数量,并加快了查询速度。
GYDataCenter 为模型对象维护内部缓存。对于给定的数据库记录,GYDataCenter 在其缓存中never 有多于一个的模型对象。这意味着无论您的代码在哪个线程上,您都会从 GYDataCenter 获取相同的模型对象副本。因此,如果您的模型对象是不可变的,您的日子将会更轻松。如果您选择将模型定义为可变的,您将需要自己解决像竞争条件等问题。例如,您可以将属性定义为原子性
@interface Employee : GYModelObject
@property (atomic, assign) NSInteger employeeId;
@property (atomic, strong) NSString *name;
@property (atomic, strong) NSDate *dateOfBirth;
@property (atomic, strong) Department *department;
@end
然而,使用不可变模型以简化应用程序中数据流的趋势日益增强。参见Facebook文章。
GYDataCenter 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。