核心数据 - 从ManyToMany关系构建NSPredicate

时间:2011-03-23 19:31:23

标签: core-data many-to-many nsfetchedresultscontroller nspredicate nsfetchrequest

这是我之前提出的问题的后续问题:

Core data: Managing employee contracts in a many-to-many relationship?

该问题有一个图表,作为快速提醒,有以下内容:

company --< contracts >-- employees

我已经能够在每个实体中手动保存1个实体,并在NSLog中验证它们。

我创建了一个列出所有公司的CompanyListPage。我们的想法是,当您点击公司时,您将看到与该公司签订合同的所有员工的列表。

如上下文所示:

Company: 
name: A

Contract:
length: 33 wks
salary: 20000

Employee:
name: Bob Jones

在我的CompanyListPage中的didSelectRowAtIndex页面中,我有以下内容。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


    Company *c = [fetchedResultsController objectAtIndexPath:indexPath];    
    NSLog(@"You clicked %@", c.name);
    NSString *companyName = c.name;

    EmployeesListPage *employeesListPage = [[EmployeesListPage alloc] initWithNibName:@"EmployeesListPage" bundle:[NSBundle mainBundle]];

    [self.navigationController pushViewController:employeesListPage animated:YES];

    employeesListPage.title = companyName;  
    employeesListPage.managedObjectContext = self.context;
    employeesListPage.managedObject = c;

    [superstarsList release];

}

然而问题是,当我最终访问employeesListPage时,我不确定我的NSPredicate应该是什么样子。

目前,它是这样的:

- (NSFetchedResultsController *)fetchedResultsController 
{

    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    // Create and configure a fetch request
    NSFetchRequest *fetchRequest    = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity     = [NSEntityDescription entityForName:@"Employees" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    // Create the sort descriptors array
    NSSortDescriptor *authorDescriptor  = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:authorDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];

    // Create and initialize the fetch results controller
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    self.fetchedResultsController = aFetchedResultsController;
    fetchedResultsController.delegate = self;

    // Memory management.
    [aFetchedResultsController release];
    [fetchRequest release];
    [authorDescriptor release];
    [sortDescriptors release];

    return fetchedResultsController;
}    

显然这是错误的,因为它不是:

a)查看合同实体 b)以任何方式,形式或形式使用公司实体

我知道我需要使用NSPredicate,但我只知道如何让它说“找到我所有合同长度大于0且与公司A合作的员工”,然后按照降序人员的名义订购,或者甚至先按最小合同长度订购。

任何关于此的指示或帮助都会很棒。谢谢。


编辑:第一次尝试(删除,因为我按照下面提供的答案让它工作)

编辑:无法获得合同信息?

我已经能够让所有为公司A工作的员工回到我的表视图控制器中。

但是我想在我的单元格中显示有关员工及其合同期限/工资的信息。

我尝试了以下内容:

Employee *emp = [fetchedResultsController objectAtIndexPath:indexPath];


NSString *firstname = emp.firstname;
NSString *surname = emp.surname;

NSString *fullname = [firstname stringByAppendingString:@" "];
fullname = [fullname stringByAppendingString:surname];

// Logging tests
NSLog(@"Name: %@", fullname); // This is fine
NSLog(@"Contracts: %@", emp.empContracts);  // This tells me of a problem with "Relationship fault for <NSRelationshipDescription: 0x602fdd0>"

我认为我需要让NSPredicate获取所有合同数据,而不仅仅是合同数据;但是我可能弄错了。

再一次,对此的帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

我认为如果您使用ANY关键字,您可以将等式的左侧恢复为单个数量,这将与等式的右侧一致:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@“ANY contracts.employer ==  %@“, employer];

答案 1 :(得分:0)

我想我现在有一个答案。

我在表视图中执行了以下操作,并获得了有效的关系和所有输出;但是我不确定我是否正确,因为它涉及一个for循环。

我使用了与我的解决方案相关的以下StackOverflow question/answer

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath 
{
    Employee *emp = [fetchedResultsController objectAtIndexPath:indexPath];

    NSString *firstname = emp.firstname;
    NSString *surname   = emp.surname;

    NSString *fullname  = [firstname stringByAppendingString:@" "];
    fullname            = [fullname stringByAppendingString:surname];

    NSLog(@"Employee: %@", fullname);

    // Output the contract deals.
    for (Contracts *deals in emp.contracts) 
    {

        NSNumber *cLength   = deals.length;
        NSNumber *cSalary   = deals.salary;

        NSLog(@"Length: %@", cLength);
        NSLog(@"Salary: %@", cSalary);
    } // next
}

我的下一步是将其包含在自定义视图中,并使用自定义标签来保存所有这些信息。

如果for循环不是最有效的方法,我欢迎任何建议/改进,甚至是最佳实践。

谢谢。

答案 2 :(得分:0)

看起来它很顺利。我想你需要的就是设置单元格的文本:cell.textLabel = fullname。

但是我不清楚你为什么要深入研究合同关系 - 直到我在顶部看你的示例文本。在那里,您想要的是雇主的合同列表,以及您希望展示其与一个员工关系和其他attrs的每个合同。在这种情况下,您根本不需要新的提取;你已经拥有了雇主,并且通过其多对多的合同关系,你也拥有合同实体,通过它们,还有工资,工资,雇员等等。

在雇主表中选择更改后,您将执行以下操作:

NSUInteger row = [indexPath row];
Employer *employer = [self.arrayOfEmployersUsedToPopulateTable objectAtIndex:row];
self.selectedEmployer = employer;
self.arrayOfSelectedEmployersContracts = [employer.contracts allObjects]; // which probably faults them, but I think that’s OK here
// Then make a call to reload the other table, the one presenting the contracts info.

在合同表中,您将返回选定的雇主,并提供每份合同的信息:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
Contract *contract = [self.arrayOfSelectedEmployersContracts objectAtIndex:row];
NSUInteger column = [indexPath column];
switch (column) {
    (0) :
    cell.textLabel = contract.length; // maybe you have to use an NSNumber method to convert to string, but probably not
    break;
    (1):
    cell.textLabel = contract.employee.firstname;
    break;
    // and so forth
}}

P.S。对于UITableCell的东西,我参考了Mark和LaMarche的“开始iPhone开发”,“使用新的表视图单元。”你可能也喜欢这本书。