[英]CoreData fetch adding an attribute based on a predicate
我有以下數據模型(簡化):
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建議的那樣,我可以使用獲取的屬性來執行此操作。 我在WordEntity
使用謂詞獲取了屬性listItemsInList
:
(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 ...
}
這可行。 不幸的是,這是非常低效的。 獲取的屬性始終返回獲取的對象數組,而不是計算值。 他們總是獲取整個對象。 最糟糕的是,它們無法預取,因此檢查表單元格中的屬性意味着每一行都有數據庫命中。 所以我仍然希望有一種更聰明的方法來做到這一點。
經過一番嘗試和錯誤之后,我找到了一個解決方案,該解決方案可以通過一次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的輸出如下所示。 我的測試數據包括各種單詞,這些單詞包含在名為Animals,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;
}, ....
我不知道如何將性能與其他解決方案進行比較!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.