【问题标题】:Realm.io - Compound primary key in objective-cRealm.io -objective-c 中的复合主键
【发布时间】:2015-08-28 18:20:19
【问题描述】:

我正在努力寻找一种使用 Realm.io 和 Objective-c 将多个属性组合成主键的方法。

以这个对象为例:

@interface Beacon : RLMObject

@property NSString *uuid;
@property int major;
@property int minor;

@end

RLM_ARRAY_TYPE(Beacon)

然后我将如何组合例如uuid、major 和 minor 合并到一个主键中?

【问题讨论】:

    标签: objective-c primary-key realm


    【解决方案1】:

    这是一个 Objective-C 解决方案。它利用了只有ignoredProperties 可以被覆盖的事实。它比 Swift 版本更冗长,但是,它可以工作,所以如果你需要 ObjC 中的复合键,这可能是你最好的选择。一个可能的限制是公共属性的 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]);
        }];
    }
    

    【讨论】:

      【解决方案2】:

      我在当前项目中的做法是为复合键添加一个新属性,使其成为主键。然后,覆盖复合键所有部分的设置器并调用更新复合键的函数。

      我的 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 中成功实现。在使用 Realm 时,似乎没有解决这个问题的标准方法?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      • 2022-11-21
      • 2015-04-27
      • 2013-06-07
      • 2013-10-23
      • 2020-03-28
      相关资源
      最近更新 更多