使用FetchedResultsController使用多对多关系从类型B的表中呈现Type对象

时间:2013-12-23 13:47:54

标签: ios core-data nsfetchedresultscontroller

我知道在SO上有类似的问题,但它们都不适用于我。

我正在编写我的第一个iOS应用程序(一个简单的书店应用程序),其模型由Book表和User表组成。他们有一个多对多的关系,称为“purchaseBook”。

Book <--purchasedBooks--> User

我正在使用fetchedResultsController在TableView中呈现这些书籍。

但我无法弄清楚如何渲染“用户数据库中所购买的书籍中的所有书籍”。即如何告诉fetchedresultscontroller迭代在User.purchsedBooks中作为集合出现的Book *对象?

基本上,我希望能够在cellForRowAtIndexPath中执行以下操作:

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

UITableViewCell* cell;
cell = [self.tableView dequeueReusableCellWithIdentifier:@"bookPlace" forIndexPath:indexPath];

// Get the book for this indexPath
Book* book = [self.fetchedResultsController objectAtIndexPath:indexPath];

cell.textLabel.text = book.title;
cell.detailTextLabel.text = book.subtitle;

return cell;
}

这是我的尝试:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
request.predicate = [NSPredicate predicateWithFormat:@"ALL purchasedBooks"];
request.sortDescriptors = @[];
self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request
                                                                   managedObjectContext:managedObjectContext
                                                                     sectionNameKeyPath:nil
                                                                              cacheName:nil];

非常感谢!

1 个答案:

答案 0 :(得分:0)

你是从错误的方向来的。您应该获取具有与您引用的用户相同的用户的PurchasedBook个实体,然后获取相关的书籍。

请注意,我将PurchasedBook视为它自己的正确实体,而不仅仅是隐藏的连接表。您可以在PurchasedBook实体中添加其他元数据,例如购买日期,价格等。

NSFetchedResultsController的创建将是:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"PurchasedBook"];
[request setPredicate:[NSPredicate predicateWithFormat@"user == %@", [self currentUser]]];
[self setFetchedResultsController:[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
BTW,实体应该始终是名义上的单数,而不是复数。请注意此代码中的更改。

使用此FetchedResultsController,您的单元格结构会稍微改变一下:

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell;
    //this should be using a static for the identifier. Magic strings are risky
    cell = [self.tableView dequeueReusableCellWithIdentifier:@"bookPlace" forIndexPath:indexPath];

    //You should make sure your cell is not nil just in case your magic string has a typo
    if (!cell) {
        //build it by hand here
    }

    // Get the book for this indexPath
    PurchasedBook* purchasedBook = [[self fetchedResultsController] objectAtIndexPath:indexPath];
    Book *book = [purchasedBook book];

    [[cell textLabel] setText:[book title]];
    [[cell detailedTextLabel] setText:[book subtitle]];

    return cell;
}

有助于停止将Core Data对象视为表。核心数据不是数据库。它是您的对象模型,恰好能够持久化到数据库。持久性是核心数据的次要功能,而不是主要功能。一旦你在脑海中颠倒了这种观点,这些类型的东西就会变得更容易解决。

更新

  

但是,能否通过用户访问图书(用户可能拥有100本左右的书籍)而不是从书本(表格?)中比较书籍(对用户)是不是更有效率可能会有50,000个物体?

不,因为您想要查看Books not Users。如果您显示的是用户列表,那么您将获取用户。这是关于获取要显示的数据的书籍。

  

Book和User之间的关系被描述为&#34;多对多&#34;在问题中。在这种情况下,谓词可能应该是&#34;任何用户==%@&#34;。

马丁指出这是正确的。但是我跳了一步。在这种情况下,您总会发现您想了解有关用户和书籍之间关系的更多信息(购买年份,书籍质量,付费价格等)并最终放置用户和书之间的对象。我在答案中添加了习惯和经验,因为我怀疑你最终会最终添加它:)