2014-09-24 129 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