CoreData获取基于谓词添加属性

时间:2014-09-24 09:04:04

标签: ios core-data

我有以下数据模型(简化):

WordEntity          ListItemEntity          ListEntity
----------          --------------          ----------
text                                        name
----------          --------------          ----------
listItems <------>> word
                    list <<---------------> items

以下基本查询:

let fetchRequest = NSFetchRequest(entityName: "WordEntity")
let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

let list = <ListEntity instance>
... do something clever here ...
controller.performFetch(nil)

我需要获取的结果包含每个对象的属性inList,如果WordEntity对象附加到ListItemEntity,而该ListItemEntity又附加到list,则该属性为true。类似于以下谓词,除了用于创建新属性而不是过滤获取请求:

NSPredicate(format: "ANY listItems.list == %@", list)

我查看了NSExpressions,但它们似乎只用于聚合,并且无法执行谓词。 SUBQUERY可以执行谓词,但仅用于过滤结果集。并且计算出的瞬态属性可以执行我想要的任何查找,但是它们无法对外部值进行操作...

我希望这很清楚......先谢谢。

更新

我能够使用获取的属性执行此操作,如pbasdf建议的那样。我在listItemsInList上有一个带谓词的获取属性WordEntity

(word == $FETCH_SOURCE) AND (list == $FETCHED_PROPERTY.userInfo.list)

然后在代码中:

let request = NSFetchRequest()
let entity = NSEntityDescription.entityForName("WordEntity", inManagedObjectContext: context)!
request.entity = entity
for property in entity.properties {
    if property.name == "listItemsInList" {
        let list = <ListEntity instance>
        (property as NSFetchedPropertyDescription).userInfo!["list"] = list
    }
}

最后:

if word.listItemsInList.count > 0 {
    ... this is what I was looking for ...
}

这很有效。不幸的是,效率非常低。获取的属性始终返回已获取对象的数组,而不是计算值。他们总是拿取整个对象。最糟糕的是,它们不能预先获取,因此检查表格单元格中的属性意味着每行都有数据库命中。所以我仍然希望有一个更聪明的方法。

1 个答案:

答案 0 :(得分:0)

经过一些试验和错误后,我找到了一个解决方案,只要您对实体的属性被返回&#34;按值&#34,就可以通过单个CoreData提取实现您想要的效果; (即它们将是一组词典中的基础属性的副本)。一个优点是字典可以包含相关对象的CoreData objectID,因此检索该对象相对简单。

诀窍是使用NSExpression,其中包括SUBQUERY(替换了相关的列表名称)和@count。这是我使用的(对不起,Obj-C再次!):

// First, get an NSAttribute description for each of the attributes we want in our query
NSEntityDescription* entity = [NSEntityDescription entityForName:@"WordEntity" inManagedObjectContext:self.context];
NSAttributeDescription *wordDesc = [entity.attributesByName objectForKey:@"word"];

// Also get an NSExpression description for the object itself
NSExpression *objIDExpression = [NSExpression expressionForEvaluatedObject];
NSExpressionDescription *objIDDescription = [[NSExpressionDescription alloc] init];
[objIDDescription setName: @"cdObjectID"];
[objIDDescription setExpression: objIDExpression];
[objIDDescription setExpressionResultType: NSObjectIDAttributeType];

// Define an expression to count a subquery
NSExpression *countExpression = [NSExpression expressionWithFormat:@"SUBQUERY(listItems,$x,$x.list.listName like %@).@count",@"Animals",nil]; 
// Note, in the above, replace @"Animals" with list.listName for the list of interest

NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName: @"count"];
[expressionDescription setExpression: countExpression];
[expressionDescription setExpressionResultType: NSInteger32AttributeType];

NSFetchRequest* fetch = [NSFetchRequest fetchRequestWithEntityName:@"WordEntity"];
[fetch setPropertiesToFetch:@[wordDesc, objIDDescription, expressionDescription]];
[fetch setResultType:NSDictionaryResultType];
NSArray *myResults = [self.context executeFetchRequest:fetch error:&error];
NSLog(@"myResults: %@",myResults);
// Recover the actual WordEntity object for the first item in myResults:
WordEntity *myWord = (WordEntity *)[self.context objectWithID:[[myResults firstObject] valueForKey:@"cdObjectID"]];

myResults的输出如下所示。我的测试数据包括我在名为Animal,Food等的列表中包含的各种单词。下面的输出是针对动物的;狗的音符数= 1!

    {
    cdObjectID = "0xd000000000040004 <x-coredata://4B6BC796-CAEF-4B0C-9B27-BC6CCDA572C7/WordEntity/p1>";
    count = 0;
    word = Orange;
},
    {
    cdObjectID = "0xd000000000080004 <x-coredata://4B6BC796-CAEF-4B0C-9B27-BC6CCDA572C7/WordEntity/p2>";
    count = 0;
    word = Geranium;
},
    {
    cdObjectID = "0xd0000000000c0004 <x-coredata://4B6BC796-CAEF-4B0C-9B27-BC6CCDA572C7/WordEntity/p3>";
    count = 0;
    word = Banana;
},
    {
    cdObjectID = "0xd000000000100004 <x-coredata://4B6BC796-CAEF-4B0C-9B27-BC6CCDA572C7/WordEntity/p4>";
    count = 1;
    word = Dog;
},
    {
    cdObjectID = "0xd000000000140004 <x-coredata://4B6BC796-CAEF-4B0C-9B27-BC6CCDA572C7/WordEntity/p5>";
    count = 0;
    word = Apple;
},
    {
    cdObjectID = "0xd000000000180004 <x-coredata://4B6BC796-CAEF-4B0C-9B27-BC6CCDA572C7/WordEntity/p6>";
    count = 1;
    word = Elephant;
}, ....

我不知道如何将性能与其他解决方案进行比较!