2015-10-08 237 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]