Realm.io - objective-c 中的复合主键
Realm.io - Compound primary key in objective-c
我正在努力寻找一种将多个属性组合成一个主键的方法,使用 Realm.io 和 Objective-c。
以这个对象为例:
@interface Beacon : RLMObject
@property NSString *uuid;
@property int major;
@property int minor;
@end
RLM_ARRAY_TYPE(Beacon)
然后我将如何组合例如uuid、major 和 minor 合并到一个主键中?
我在当前项目中的做法是为复合键添加一个新的 属性,使其成为主键。然后,覆盖复合键所有部分的设置器并调用更新复合键的函数。
我的 ObjC 很弱,所以我无法为您提供用该语言编写的可靠示例,但是 Swift 中的示例可能会有所帮助。
class Thing: Object {
dynamic var part1: String = "" {
didSet {
self.updateCompoundKey()
}
}
dynamic var part2: String = "" {
didSet {
self.updateCompoundKey()
}
}
dynamic var compoundKey: String = ""
override static func primaryKey() -> String? {
return "compoundKey"
}
private func updateCompoundKey() {
self.compoundKey= "\(self.part1)\(self.part2)"
}
}
这是一个 Objective-C 解决方案。它利用了只能覆盖 ignoredProperties
的事实。它比 Swift 版本更冗长,但是它可以工作,所以如果您需要 ObjC 中的复合键,这可能是您最好的选择。一个可能的限制是 public 属性的 KVO 将不起作用,但是,由于 Realm 期望主键在对象添加到 Realm 后保持不变,所以这个限制可能很小。如果您确实需要 KVO,您可能可以通过 in this document from Apple.
中描述的注册依赖键来绕过它
在CompositeKeyObject.h中:
@interface CompositeKeyObject : RLMObject
@property (nonatomic, strong) NSString* partOne;
@property (nonatomic, strong) NSString* partTwo;
@end
在CompositeKeyObject.m中:
@interface CompositeKeyObject ()
@property (nonatomic, strong) NSString* partOneValue;
@property (nonatomic, strong) NSString* partTwoValue;
@property (nonatomic, strong) NSString* compositeKey;
@end
@implementation CompositeKeyObject
- (instancetype)initWithValue:(id)value
{
// Need to make a copy and set the correct "value" properties.
// Otherwise, the object won't be created properly.
NSMutableDictionary* valueCopy = [value mutableCopy];
if(valueCopy[@"partOne"] != nil) {
valueCopy[@"partOneValue"] = valueCopy[@"partOne"];
}
if(valueCopy[@"partTwo"] != nil) {
valueCopy[@"partTwoValue"] = valueCopy[@"partTwo"];
}
self = [super initWithValue:[valueCopy copy]];
if(self != nil) {
// Make sure primary key is in sync.
[self updatePrimaryKey];
}
return self;
}
- (void)setPartOne:(NSString *)partOne
{
self.partOneValue = partOne;
[self updatePrimaryKey];
}
- (void)setPartTwo:(NSString *)partTwo
{
self.partTwoValue = partTwo;
[self updatePrimaryKey];
}
- (NSString*)partOne
{
return self.partOneValue;
}
- (NSString*)partTwo
{
return self.partTwoValue;
}
- (void)updatePrimaryKey
{
self.compositeKey = [NSString stringWithFormat:@"%@ <><><> %@", self.partOne, self.partTwo];
}
+ (NSString *)primaryKey
{
return @"compositeKey";
}
+ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args {
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partOne" withString:@"partOneValue"];
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partTwo" withString:@"partTwoValue"];
return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
}
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args {
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partOne" withString:@"partOneValue"];
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partTwo" withString:@"partTwoValue"];
return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
}
@end
单元测试:
- (void)testCompositeObject
{
CompositeKeyObject* object = [[CompositeKeyObject alloc] init];
object.partOne = @"ONE";
object.partTwo = @"TWO";
RLMRealm* realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:object];
}];
XCTAssertNotNil([CompositeKeyObject objectForPrimaryKey:@"ONE <><><> TWO"]);
object = [[CompositeKeyObject alloc] init];
object.partOne = @"ONE";
object.partTwo = @"TWO";
[realm transactionWithBlock:^{
XCTAssertThrows([realm addObject:object]);
}];
}
- (void)testCompositeObject2
{
CompositeKeyObject* object = [[CompositeKeyObject alloc] initWithValue:@{@"partOne": @"ONE", @"partTwo": @"TWO"}];
RLMRealm* realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:object];
}];
XCTAssertNotNil([CompositeKeyObject objectForPrimaryKey:@"ONE <><><> TWO"]);
object = [[CompositeKeyObject alloc] initWithValue:@{@"partOne": @"ONE", @"partTwo": @"TWO"}];
[realm transactionWithBlock:^{
XCTAssertThrows([realm addObject:object]);
}];
}
我正在努力寻找一种将多个属性组合成一个主键的方法,使用 Realm.io 和 Objective-c。
以这个对象为例:
@interface Beacon : RLMObject
@property NSString *uuid;
@property int major;
@property int minor;
@end
RLM_ARRAY_TYPE(Beacon)
然后我将如何组合例如uuid、major 和 minor 合并到一个主键中?
我在当前项目中的做法是为复合键添加一个新的 属性,使其成为主键。然后,覆盖复合键所有部分的设置器并调用更新复合键的函数。
我的 ObjC 很弱,所以我无法为您提供用该语言编写的可靠示例,但是 Swift 中的示例可能会有所帮助。
class Thing: Object {
dynamic var part1: String = "" {
didSet {
self.updateCompoundKey()
}
}
dynamic var part2: String = "" {
didSet {
self.updateCompoundKey()
}
}
dynamic var compoundKey: String = ""
override static func primaryKey() -> String? {
return "compoundKey"
}
private func updateCompoundKey() {
self.compoundKey= "\(self.part1)\(self.part2)"
}
}
这是一个 Objective-C 解决方案。它利用了只能覆盖 ignoredProperties
的事实。它比 Swift 版本更冗长,但是它可以工作,所以如果您需要 ObjC 中的复合键,这可能是您最好的选择。一个可能的限制是 public 属性的 KVO 将不起作用,但是,由于 Realm 期望主键在对象添加到 Realm 后保持不变,所以这个限制可能很小。如果您确实需要 KVO,您可能可以通过 in this document from Apple.
在CompositeKeyObject.h中:
@interface CompositeKeyObject : RLMObject
@property (nonatomic, strong) NSString* partOne;
@property (nonatomic, strong) NSString* partTwo;
@end
在CompositeKeyObject.m中:
@interface CompositeKeyObject ()
@property (nonatomic, strong) NSString* partOneValue;
@property (nonatomic, strong) NSString* partTwoValue;
@property (nonatomic, strong) NSString* compositeKey;
@end
@implementation CompositeKeyObject
- (instancetype)initWithValue:(id)value
{
// Need to make a copy and set the correct "value" properties.
// Otherwise, the object won't be created properly.
NSMutableDictionary* valueCopy = [value mutableCopy];
if(valueCopy[@"partOne"] != nil) {
valueCopy[@"partOneValue"] = valueCopy[@"partOne"];
}
if(valueCopy[@"partTwo"] != nil) {
valueCopy[@"partTwoValue"] = valueCopy[@"partTwo"];
}
self = [super initWithValue:[valueCopy copy]];
if(self != nil) {
// Make sure primary key is in sync.
[self updatePrimaryKey];
}
return self;
}
- (void)setPartOne:(NSString *)partOne
{
self.partOneValue = partOne;
[self updatePrimaryKey];
}
- (void)setPartTwo:(NSString *)partTwo
{
self.partTwoValue = partTwo;
[self updatePrimaryKey];
}
- (NSString*)partOne
{
return self.partOneValue;
}
- (NSString*)partTwo
{
return self.partTwoValue;
}
- (void)updatePrimaryKey
{
self.compositeKey = [NSString stringWithFormat:@"%@ <><><> %@", self.partOne, self.partTwo];
}
+ (NSString *)primaryKey
{
return @"compositeKey";
}
+ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args {
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partOne" withString:@"partOneValue"];
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partTwo" withString:@"partTwoValue"];
return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
}
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args {
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partOne" withString:@"partOneValue"];
predicateFormat = [predicateFormat stringByReplacingOccurrencesOfString:@"partTwo" withString:@"partTwoValue"];
return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
}
@end
单元测试:
- (void)testCompositeObject
{
CompositeKeyObject* object = [[CompositeKeyObject alloc] init];
object.partOne = @"ONE";
object.partTwo = @"TWO";
RLMRealm* realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:object];
}];
XCTAssertNotNil([CompositeKeyObject objectForPrimaryKey:@"ONE <><><> TWO"]);
object = [[CompositeKeyObject alloc] init];
object.partOne = @"ONE";
object.partTwo = @"TWO";
[realm transactionWithBlock:^{
XCTAssertThrows([realm addObject:object]);
}];
}
- (void)testCompositeObject2
{
CompositeKeyObject* object = [[CompositeKeyObject alloc] initWithValue:@{@"partOne": @"ONE", @"partTwo": @"TWO"}];
RLMRealm* realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:object];
}];
XCTAssertNotNil([CompositeKeyObject objectForPrimaryKey:@"ONE <><><> TWO"]);
object = [[CompositeKeyObject alloc] initWithValue:@{@"partOne": @"ONE", @"partTwo": @"TWO"}];
[realm transactionWithBlock:^{
XCTAssertThrows([realm addObject:object]);
}];
}