2014-09-24 229 views
1

我有以下数据模型(简化的)添加属性:CoreData取指基于谓词

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建议。我有一个牵强财产listItemsInListWordEntity与谓词:

(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 ... 
} 

这工作。不幸的是它效率很低。获取的属性总是返回获取对象的数组,而不是计算值。他们总是抓取整个物体。最糟糕的是,它们不能被预取,所以检查表格单元格中的属性意味着每行都有一个数据库命中。所以我仍然希望有一个更聪明的方法来做到这一点。

+0

你看过Fetched Properties吗? – pbasdf 2014-09-24 10:59:57

+0

谢谢。我不认为这是可以取得的属性,但我再次尝试你的建议,我得到它的工作。我已经用细节更新了这个问题。 – user1498059 2014-09-25 05:05:52

+0

如果你只是想检查一个给定的单词是否在给定的列表中,请尝试'if([word.listItems intersectsSet:list.items]){...}'(对不起,Objective-C)。 – pbasdf 2014-09-25 08:35:38

回答

0

经过一些试验和错误,我发现一个解决方案可以实现你想要的一个CoreData提取,只要你满意实体的属性被“按价值”返回(即它们将是在字典数组中的基础属性)。保存宽限的一个原因是字典可以包含相关对象的CoreData对象ID,因此检索该对象相对简单。

诀窍是使用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 %@)[email protected]",@"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的输出如下所示。我的测试数据包括我列入名为动物,食物等列表中的各种词语。下面的输出是针对动物的;注意狗数= 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; 
}, .... 

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

+0

谢谢!这正是我希望能够做到的事情。 – user1498059 2014-09-30 11:22:59