核心数据 - 从多对多关系构建 NSPredicate

Posted

技术标签:

【中文标题】核心数据 - 从多对多关系构建 NSPredicate【英文标题】:Core data - Building a NSPredicate from a ManyToMany relationship 【发布时间】:2011-03-23 19:31:22 【问题描述】:

这是我上一个问题的后续问题:

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 获取所有合约数据,而不仅仅是合约数据;但是我可能弄错了。

再次,我们将不胜感激。

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

我会试一试的。谢谢。 它似乎在工作,我的 tableViewController 中有一个为公司工作的员工列表。但我在取回合同信息时遇到了困难。我已经用确切的问题修改了我原来的问题。【参考方案2】:

我想我现在有答案了。

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

我在解决方案中使用了以下与 *** 相关的 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 循环不是最有效的方法,我欢迎任何建议/改进,甚至是被认为是最佳实践的方法。

谢谢。

【讨论】:

【参考方案3】:

看起来进展顺利。我认为您需要的只是设置单元格的文本:cell.textLabel = fullname。

但我不清楚你为什么要重新研究合同关系——直到我查看了顶部的示例文本。在那里,看起来您想要的是雇主的合同列表,并且对于每个合同,您都希望显示其一对一的员工关系和其他属性。在这种情况下,您根本不需要新的 fetch;您已经有了雇主,并且通过它的多对合同关系,您还拥有合同实体,并通过它们获得期限、薪水、雇员等。

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

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

附:对于 UITableCell 的内容,我咨询了 Mark 和 LaMarche 撰写的“开始 iPhone 开发”,“使用新的 Table View Cell”。你可能也喜欢这本书。

【讨论】:

糟糕,我一直在使用 NSTableView,所以我正在考虑使用 selectionDidChange 委托方法来缓存雇主对象。您可能正在深入查看详细信息表视图。您会以某种方式从超级视图中检索雇主对象。很抱歉造成混乱。 感谢您的帮助。我很感激。我重新研究合同关系的原因是因为 a) 我想要恢复合同期限和合同工资。我希望能够按长度对整个提取进行排序(即:给我一份合同即将到期的人员名单)。我会看看这本书。我有几本 Core Data 书籍,需要学习的内容很多。我会尽快详细探讨您的答案。

以上是关于核心数据 - 从多对多关系构建 NSPredicate的主要内容,如果未能解决你的问题,请参考以下文章

使用实体框架从多对多关系中选择数据

从多对多关系中获取数据

从多对多关系的桥接表中检索数据的查询[关闭]

使用非关联数据 (LINQ) 从多对多关系中获取值

如何在 Laravel 中从多对多关系的一对多关系中获取项目?

Django 从多对多关系中删除对象