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

发布于 2024-10-26 01:21:21 字数 3746 浏览 1 评论 0原文

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

核心数据:以多对多关系管理员工合同?

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

company --< Contract >--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];

}

然而问题是,当我最终转到员工列表页面时,我不确定我的 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 来获取所有合约数据,而不仅仅是合约数据;然而我可能错了。

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

This is a follow up question to my previous question on:

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

There is a diagram on that question, and as a quick reminder there is the following:

company --< contracts >-- employees

I have been able to manually save 1 entity inside each of the entities, and verified them all in NSLog.

I've created a CompanyListPage which lists all companies. The idea is that when you click on a company you will be presented with a list of all employees who have a contract with said company.

As context see below:

Company: 
name: A

Contract:
length: 33 wks
salary: 20000

Employee:
name: Bob Jones

In my didSelectRowAtIndex page within my CompanyListPage I have the following.

- (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];

}

The problem however is, I am not sure what my NSPredicate should look like when I eventually go to the employeesListPage.

At the moment, its this:

- (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;
}    

Obviously this is wrong, because its not:

a) Looking in the contracts entity
b) Using the company entity in any way, shape or form

I know I need to use a NSPredicate, but I just know how to make it say "Find me all the employees with a contract length > 0 and working with company A" then order it by the name of the person descending, or even order it by the least contract length first.

Any pointers or help on this would be great. Thank you.


EDIT: First attempt (removed because I got it to work following an answer provided below)

EDIT: Unable to get contract information back?

I've been able to get all the employees that work for Company A back in my table view controller.

However I'm wanting to display in my cell information about the employee and their contract length/salary.

I've tried the following:

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>"

I believe I need to get the NSPredicate to grab all the contract data, and not just the contract data; however I may be mistaken.

Again, help on this would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜未央樱花落 2024-11-02 01:21:21

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

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

I think if you use the ANY keyword, you'll restore the left side of the equation to a single quantity, which will agree with the right side of the equation:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@“ANY contracts.employer ==  %@“, employer];
卸妝后依然美 2024-11-02 01:21:21

我想我现在有了答案。

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

我使用了以下 StackOverflow 相关 question/回答我的解决方案。

- (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 循环不是最有效的方法,我欢迎任何建议/改进,甚至是被认为是最佳实践的方法。

谢谢。

I think I have an answer now.

I did the following in my table view and got a valid relationship and all the output; however I am not sure if I am doing it right because it involves a for-loop.

I used the following StackOverflow related question/answer for my solution.

- (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
}

The next step for me is to include this in a custom view with custom labels to hold all this info.

If the for-loop is not the most efficient way to do this, I would welcome any suggestions/improvements, or even what is considered best practice.

Thank you.

墟烟 2024-11-02 01:21:21

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

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

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

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
}}

PS 对于 UITableCell 内容,我咨询了 Beginning iPhone Development,作者: Mark 和 LaMarche,“使用新的表视图单元格。”你可能也喜欢这本书。

Looks like it’s coming along well. I think all you need from there is to set the cell’s text: cell.textLabel = fullname.

But I’m not clear why you’re delving back into the contracts relationship — until I look at your sample text at the top. There, it looks like what you want is a list of contracts for the employer, and for each contract you want to show its to-one employee relationship and other attrs. In which case you don’t need a new fetch at all; you already have the employer and, through its to-many contracts relationship, you also have the contracts entities and, through them, the term, salary, employee, whatever.

Upon selection change in the employers table, you would do something like this:

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.

In the contracts table, you’d refer back to the selected employer, and present info for each contract:

- (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. For the UITableCell stuff, I consulted Beginning iPhone Development, by Mark and LaMarche, “Using the New Table View Cell.” You might like this book too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文