Realm Cocoa:通过PK找到多个对象

时间:2015-01-06 12:40:31

标签: ios objective-c realm

长时间潜伏,第一次问问。

我在一个项目中使用Realm Cocoa(来自Realm.io)并且正在努力通过PK进行搜索。 我们假设我有一个名为RLMFoo的实体,它有一个名为bar的主键。我还有一个PK列表,让我们说存储在一个数组中:

NSArray *primaryKeys = @[@"bar1", @"bar2", @"bar3"]

有没有办法在一个查询中从我的领域中检索类RLMFoo的所有实体?

我到目前为止已尝试过:

  1. 谓词格式:[RLMFoo objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:@"bar IN %@", primaryKeys]];
  2. 境界的地方:[RLMFoo objectsInRealm:realm where:@"bar IN %@", strippedIds];
  3. 用块谓语:
  4. NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id
    evaluatedObject, NSDictionary *bindings) {
                        RLMFoo *foo = (RLMFoo *)evaluatedObject;
                        return [primaryKeys containsObject:foo.bar];
                    }];
            [RLMFoo objectsInRealm:realm withPredicate:predicate];
    

    但到目前为止我发现的唯一工作就是查询每个主键值的领域并聚合结果,这似乎很慢:

    NSMutableArray *results = [NSMutableArray new];
    for (NSString *primaryKey in primaryKeys) {
        RLMFoo *obj = [RLMFoo objectInRealm:realm forPrimaryKey:primaryKey];
        if (obj) {
            [results addObject:obj];
        }
    }
    

    有谁知道更好的方法吗?

    =========解释为什么前三种方法不起作用=======

    1)从异常消息中可以看出这不起作用的原因:IN只需要2个值,尽管IN的SQL版本应该尽可能多地使用。正如我们从RLMQueryUtil.mm的源代码中看到的那样,这同样适用于BETWEEN运算符:

            if (compp.predicateOperatorType == NSBetweenPredicateOperatorType || compp.predicateOperatorType == NSInPredicateOperatorType) {
            // Inserting an array via %@ gives NSConstantValueExpressionType, but
            // including it directly gives NSAggregateExpressionType
            if (exp1Type != NSKeyPathExpressionType || (exp2Type != NSAggregateExpressionType && exp2Type != NSConstantValueExpressionType)) {
                @throw RLMPredicateException(@"Invalid predicate",
                                             @"Predicate with %s operator must compare a KeyPath with an aggregate with two values",
                                             compp.predicateOperatorType == NSBetweenPredicateOperatorType ? "BETWEEN" : "IN");
            }
    

    这是堆栈跟踪:

    *** Terminating app due to uncaught exception 'Invalid predicate', reason: 'Predicate with IN operator must compare a KeyPath with an aggregate with two values'
    *** First throw call stack:
    (
        0   CoreFoundation      0x03334946 __exceptionPreprocess + 182
        1   libobjc.A.dylib     0x0292aa97 objc_exception_throw + 44
        2   <redacted>          0x00190569 _ZN12_GLOBAL__N_127update_query_with_predicateEP11NSPredicateP9RLMSchemaP15RLMObjectSchemaRN7tightdb5QueryE + 2553
        3   <redacted>          0x0018f7ea _Z27RLMUpdateQueryWithPredicatePN7tightdb5QueryEP11NSPredicateP9RLMSchemaP15RLMObjectSchema + 378
        4   <redacted>          0x0018b23c _Z13RLMGetObjectsP8RLMRealmP8NSStringP11NSPredicate + 748
        5   <redacted>          0x0017d721 +[RLMObject objectsInRealm:withPredicate:] + 161
    

    2)这在理由和堆栈跟踪中非常相似:

    *** Terminating app due to uncaught exception 'Invalid predicate', reason: 'Predicate with IN operator must compare a KeyPath with an aggregate with two values'
    *** First throw call stack:
    (
        0   CoreFoundation      0x03328946 __exceptionPreprocess + 182
        1   libobjc.A.dylib     0x0291ea97 objc_exception_throw + 44
        2   <redacted>          0x00184599 _ZN12_GLOBAL__N_127update_query_with_predicateEP11NSPredicateP9RLMSchemaP15RLMObjectSchemaRN7tightdb5QueryE + 2553
        3   <redacted>          0x0018381a _Z27RLMUpdateQueryWithPredicatePN7tightdb5QueryEP11NSPredicateP9RLMSchemaP15RLMObjectSchema + 378
        4   <redacted>          0x0017f26c _Z13RLMGetObjectsP8RLMRealmP8NSStringP11NSPredicate + 748
        5   <redacted>          0x00171751 +[RLMObject objectsInRealm:withPredicate:] + 161
        6   <redacted>          0x00171465 +[RLMObject objectsInRealm:where:args:] + 213
        7   <redacted>          0x001712f3 +[RLMObject objectsInRealm:where:] + 419
    

    3)这个也非常相似。归结为Ncpredicate的完整功能集缺乏对领域的支持。

    *** Terminating app due to uncaught exception 'Invalid predicate', reason: 'Only support compound and comparison predicates'
    *** First throw call stack:
    (
        0   CoreFoundation      0x03308946 __exceptionPreprocess + 182
        1   libobjc.A.dylib     0x028fea97 objc_exception_throw + 44
        2   <redacted>          0x001638bd _ZN12_GLOBAL__N_127update_query_with_predicateEP11NSPredicateP9RLMSchemaP15RLMObjectSchemaRN7tightdb5QueryE + 4397
        3   <redacted>          0x0016240a _Z27RLMUpdateQueryWithPredicatePN7tightdb5QueryEP11NSPredicateP9RLMSchemaP15RLMObjectSchema + 378
        4   <redacted>          0x0015de5c _Z13RLMGetObjectsP8RLMRealmP8NSStringP11NSPredicate + 748
        5   <redacted>          0x00150341 +[RLMObject objectsInRealm:withPredicate:] + 161
    

2 个答案:

答案 0 :(得分:4)

你的前两个选项应该没问题。编写此查询的最简单方法是:

NSArray *primaryKeys = @[@"bar1", @"bar2", @"bar3"]
RLMResults *results = [RLMFoo objectsWhere:@"id IN %@", primaryKeys];

一个名为objectsWithPredicate的方法也可以。使用前几种方法时,您能分享更多的代码/堆栈跟踪吗?我认为其他地方还有问题

答案 1 :(得分:2)

在你的帮助下,我找到了这种行为的原因。 我的真实代码更贴近:

  NSArray *primaryKeys = @[ @"bar1", @"bar2", @"bar3" ];

  NSString *primaryKeyName = @"bar";
  RLMResults *results =
      [RLMFoo objectsInRealm:self.realm
               withPredicate:[NSPredicate predicateWithFormat:@"%@ IN %@",
                                                              primaryKeyName,
                                                              primaryKeys]];

在方法中,PK和PK名称是方法调用的参数。理论上,这将允许我的类检索具有任何PK名称的任何对象。 原来我的错误在于假设predicateWithFormat会在这种情况下以与stringWithFormat类似的方式工作,并正确地将PK名称替换为第一个参数,并将PK阵列作为第二个参数。然而,解决方案结果是首先组装格式字符串,然后是谓词:

  RLMResults *results = [RLMFoo
      objectsInRealm:self.realm
       withPredicate:[NSPredicate
                         predicateWithFormat:
                             [NSString stringWithFormat:@"%@ IN %%@", primaryKeyName],
                             primaryKeys]];

感谢Yoshyosh的时间。