2015-10-08 249 views
0

我有一個SQL命令,這對於使用普通SQL來構建將會非常簡單,但是我在使用Core Data時遇到了很多麻煩。NSPredicate和核心數據多表查詢

我有3個實體;項目,文件夾和組。項目位於文件夾中,而文件夾位於組中。通過文件夾名稱和組名稱使文件夾變得唯一。項目只存儲文件夾名稱,而文件夾存儲文件夾名稱和組名稱。

有問題的SQL命令大致是這樣的:SELECT ItemID FROM Item WHERE Item.folderName = folderName AND Folder.folderName = Item.folderName AND Folder.groupName = groupName;

(是的,我知道我沒有得到與CoreData特定屬性,我只是在做它的例子)

問題當我做Folder.folderName = Item.folderName AND Folder.groupName = groupName部分時出現。我無法弄清楚如何將其作爲謂詞來表示。

我應該注意到,我在項目和文件夾之間以及文件夾和組之間存在關係。

編輯:

這是我的數據模型的建立:

Data Setup

這是我現在使用提出請求的代碼:

NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"FavouriteItem" inManagedObjectContext:context]; 

[request setEntity:entity]; 

request.predicate = [NSPredicate predicateWithFormat:@"folderName = %@ AND folderRelationship.groupName = %@", self.folderName, self.groupName]; 

NSError *fetchError; 

NSArray *results = [context executeFetchRequest:request error:&fetchError]; 
+0

是item.folderName的其包含文件夾的名稱和item.folder.folderName相同? – Willeke

+0

如果你有關係,你爲什麼不使用它們? – quellish

+0

@Willeke,是的。冷靜,因爲我不知道如何和我被可用的文件混淆。 – JamEngulfer

回答

1

所以,基本上,您想要獲取特定文件夾中的所有項目(即,您希望具有給定folderName和groupName ...的所有項目唯一標識特定文件夾)。

既然你說你已經有了關係,我會假設他們是以反向關係設置的。

此外,我將假定一個項目具有名爲「文件夾」的一對一關係,該關係是該項目所在的文件夾。該文件夾將具有該項目文件夾中項目的多對多關係「項目」。

因此,以下將是許多方法來完成你想要的東西之一。

- (NSSet*)getItemsForFolderName:(NSString*)folderName 
         groupName:(NSString*)groupName 
          inMOC:(NSManagedObjectContext*)moc 
          error:(NSError**)error { 
    NSSet *result = nil; 
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Folder"]; 
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"folderName = %@ AND groupName = %@", folderName, groupName]; 
    fetchRequest.relationshipKeyPathsForPrefetching = @[@"items"]; 
    NSArray *folders = [moc executeFetchRequest:fetchRequest error:error]; 
    if (folders) { 
     result = [[folders firstObject] items]; 
    } 
    return result; 
} 

您也可以簡單地獲取項目。至於哪個最好,這取決於你如何擁有你的屬性索引,以及你正在做什麼類型的其他提取。

- (NSArray*)getItemsForFolderName:(NSString*)folderName 
         groupName:(NSString*)groupName 
          inMOC:(NSManagedObjectContext*)moc 
          error:(NSError**)error { 
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Item"]; 
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"folderName = %@ AND folder.groupName = %@", folderName, groupName]; 
    return [moc executeFetchRequest:fetchRequest error:error]; 
} 

編輯

JamEngulfer221,我敢肯定這些例子會的工作,但因爲你說他們甚至沒有經過我指出在您的文章中的錯誤,我想我會砍一個快速的項目和測試...我老了,有時忘記的東西...

所以,我砍了一個測試,用下面的代碼。

首先,創建模型...

- (NSManagedObjectModel *)makeModel { 
    NSEntityDescription *group = [[NSEntityDescription alloc] init]; 
    group.name = @"Group"; 
    NSAttributeDescription *groupName = [[NSAttributeDescription alloc] init]; 
    groupName.name = @"groupName"; 
    groupName.attributeType = NSStringAttributeType; 

    NSEntityDescription *folder = [[NSEntityDescription alloc] init]; 
    folder.name = @"Folder"; 
    NSAttributeDescription *folderName = [[NSAttributeDescription alloc] init]; 
    folderName.name = @"folderName"; 
    folderName.attributeType = NSStringAttributeType; 

    NSEntityDescription *item = [[NSEntityDescription alloc] init]; 
    item.name = @"Item"; 
    NSAttributeDescription *itemName = [[NSAttributeDescription alloc] init]; 
    itemName.name = @"itemName"; 
    itemName.attributeType = NSStringAttributeType; 

    NSRelationshipDescription *folderToGroupRelationship = [[NSRelationshipDescription alloc] init]; 
    NSRelationshipDescription *groupToFoldersRelationship = [[NSRelationshipDescription alloc] init]; 

    groupToFoldersRelationship.name = @"folders"; 
    groupToFoldersRelationship.destinationEntity = folder; 
    groupToFoldersRelationship.minCount = 0; 
    groupToFoldersRelationship.maxCount = 0; 
    groupToFoldersRelationship.deleteRule = NSCascadeDeleteRule; 
    groupToFoldersRelationship.inverseRelationship = folderToGroupRelationship; 

    folderToGroupRelationship.name = @"group"; 
    folderToGroupRelationship.destinationEntity = group; 
    folderToGroupRelationship.minCount = 0; 
    folderToGroupRelationship.maxCount = 1; 
    folderToGroupRelationship.deleteRule = NSNullifyDeleteRule; 
    folderToGroupRelationship.inverseRelationship = groupToFoldersRelationship; 

    NSRelationshipDescription *folderToItemsRelationship = [[NSRelationshipDescription alloc] init]; 
    NSRelationshipDescription *itemToFolderRelationship = [[NSRelationshipDescription alloc] init]; 

    folderToItemsRelationship.name = @"items"; 
    folderToItemsRelationship.destinationEntity = item; 
    folderToItemsRelationship.minCount = 0; 
    folderToItemsRelationship.maxCount = 0; 
    folderToItemsRelationship.deleteRule = NSCascadeDeleteRule; 
    folderToItemsRelationship.inverseRelationship = itemToFolderRelationship; 

    itemToFolderRelationship.name = @"folder"; 
    itemToFolderRelationship.destinationEntity = folder; 
    itemToFolderRelationship.minCount = 0; 
    itemToFolderRelationship.maxCount = 1; 
    itemToFolderRelationship.deleteRule = NSNullifyDeleteRule; 
    itemToFolderRelationship.inverseRelationship = folderToItemsRelationship; 

    group.properties = @[groupName, groupToFoldersRelationship]; 
    folder.properties = @[folderName, groupName, folderToGroupRelationship, folderToItemsRelationship]; 
    item.properties = @[itemName, folderName, itemToFolderRelationship]; 

    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] init]; 
    model.entities = @[group, folder, item]; 
    return model; 
} 

而且搜索方法...

- (NSArray*)getItemsForFolderName:(NSString*)folderName 
         groupName:(NSString*)groupName 
          inMOC:(NSManagedObjectContext*)moc 
          error:(NSError**)error { 
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Item"]; 
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"folderName = %@ AND folder.groupName = %@", folderName, groupName]; 
    return [moc executeFetchRequest:fetchRequest error:error]; 
} 

並且測試...

- (void)testBlarg { 
    NSManagedObjectModel *model = [self makeModel]; 
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; 
    [psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL]; 
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
    moc.persistentStoreCoordinator = psc; 

    for (int g = 0; g < 10; ++g) { 
     NSManagedObject *group = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:moc]; 
     NSString *groupName = [NSString stringWithFormat:@"Group %02d", g]; 
     [group setValue:groupName forKey:@"groupName"]; 
     for (int f = 0; f < 10; ++f) { 
      NSManagedObject *folder = [NSEntityDescription insertNewObjectForEntityForName:@"Folder" inManagedObjectContext:moc]; 
      NSString *folderName = [NSString stringWithFormat:@"Folder %02d", f]; 
      [folder setValue:folderName forKey:@"folderName"]; 
      [folder setValue:groupName forKey:@"groupName"]; 
      [folder setValue:group forKey:@"group"]; 
      for (int i = 0; i < 10; ++i) { 
       NSManagedObject *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:moc]; 
       NSString *itemName = [NSString stringWithFormat:@"Item %02d (%@;%@)", i, folderName, groupName]; 
       [item setValue:itemName forKey:@"itemName"]; 
       [item setValue:folderName forKey:@"folderName"]; 
       [item setValue:folder forKey:@"folder"]; 
      } 
     } 
    } 
    [moc save:NULL]; 
    [moc reset]; 

    NSString *folderName = @"Folder 04"; 
    NSString *groupName = @"Group 02"; 
    NSArray *items = [self getItemsForFolderName:folderName groupName:groupName inMOC:moc error:NULL]; 
    items = [items sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"itemName" ascending:YES]]]; 
    XCTAssertEqual(10, items.count); 
    for (int i = 0; i < 10; ++i) { 
     NSManagedObject *object = items[i]; 
     NSString *expectedItemName = [NSString stringWithFormat:@"Item %02d (%@;%@)", i, folderName, groupName]; 
     XCTAssertEqualObjects(expectedItemName, [object valueForKey:@"itemName"]); 
     NSManagedObject *folder = [object valueForKey:@"folder"]; 
     XCTAssertEqualObjects(folderName, [folder valueForKey:@"folderName"]); 
     XCTAssertEqualObjects(groupName, [folder valueForKey:@"groupName"]); 
     NSManagedObject *group = [folder valueForKey:@"group"]; 
     XCTAssertEqualObjects(groupName, [group valueForKey:@"groupName"]); 
    } 
} 
+0

我試過你的第二個選項,它似乎沒有工作。我已經建立了關係,但是當我提出請求時,我得到了0個結果。 – JamEngulfer

+0

然後,也許你沒有像你認爲的那樣建立你的關係;-)爲什麼不張貼你的模型細節和你用來做查詢的確切代碼的截圖(注意我做的假設)。 –

+0

好吧,我用圖像和我的代碼更新了原始帖子。希望有幫助 – JamEngulfer

0

我認爲你的數據模型的設置是有缺陷的,造成這種混亂。其實,你的問題很簡單。

首先,如果一個項目被分配到一個文件夾,您不需要存儲文件夾名稱 - 這將是多餘的,因此是不必要的信息。這同樣適用於文件夾和組名。

其次,父文件夾應該是同一個實體的反身關係,而不是屬性。

所有實體應該只是有一個name屬性,這些關係(注意直觀的非技術關係名稱):

Group (folders)  <------>> (group) Folder (items) <------->> (folder) Item 
Folder (subFolders) <------>> (parentFolder) Folder 

謂詞現在是微不足道的:

[NSPredicate predicateWithFormat: 
    @"folder.name = %@ && folder.group.name = %@", folderName, groupName]