在 Core Data 中获取具有关系的实体

Posted

技术标签:

【中文标题】在 Core Data 中获取具有关系的实体【英文标题】:Fetching entities with relations in Core Data 【发布时间】:2011-07-08 20:01:11 【问题描述】:

我的核心数据数据库中有 2 个实体 PersonPhoto PersonPhoto 具有 To-Many 关系,PhotoPerson (Person<-->>Photo) 具有反向关系。我通过以下方式从 .plist 中为我的应用加载一些初始数据:

-(void)populateDataStorage

    NSString *path = [[NSBundle mainBundle] pathForResource:@"FakeData" ofType:@"plist"];

    if(path)
        NSArray *plistData = [[NSArray alloc] initWithContentsOfFile:path];
        NSEnumerator *enumerator = [plistData objectEnumerator];

        NSArray *personResults;

        Photo *photo;
        Person *person;

        id currItem = [enumerator nextObject];

        while (currItem != nil) 
            photo = (Photo *)[NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:[flickrFetcher managedObjectContext]];

            photo.name = [currItem objectForKey:@"name"];
            photo.path = [currItem objectForKey:@"path"];

            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", [currItem objectForKey:@"user"]];

            personResults = [flickrFetcher fetchManagedObjectsForEntity:@"Person" withPredicate:predicate];

            if ([personResults count] > 0) 
                person = [personResults objectAtIndex:0];
             
            else 
                person = (Person *)[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:[flickrFetcher managedObjectContext]];
                person.name = [currItem objectForKey:@"user"];
            

            photo.person = person;
            [person addPhotosObject:photo];

            NSLog(@"Photo %@ added for user %@", photo.name, person.name);

            currItem = [enumerator nextObject];
        

        [plistData release];

    


一切都正确加载。然后我使用NSFetchedResultsController 获取Person 并加载UITableView,一切正常。当用户单击属于某个用户的单元格时,我必须使用所选人员的照片加载另一个 UITableView,因此我在 UITableViewController 中为我的照片表视图执行以下操作:

 - (id)initWithStyle:(UITableViewStyle)style

    self = [super initWithStyle:style];
    if (self) 
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"person = %@", person];
        self.fetchedResultsController = [[FlickrFetcher sharedInstance] fetchedResultsControllerForEntity:@"Photo" withPredicate:predicate];
    
    return self;

在我的viewDidLoad

- (void)viewDidLoad

    [super viewDidLoad];

    NSError *error = nil;
    [fetchedResultsController performFetch:&error];

    for(Photo *photo in person.photos)
        NSLog(@"Photo %@ belongs to %@", photo.name, person.name);
    

    NSLog(@"Photo count %d", [[fetchedResultsController fetchedObjects] count]);

计数给我 0,我从未得到此人的照片,但我知道它们已正确保存,因为它们都为传入的 Person 打印出来。知道我可能做错了什么吗?

编辑

在我的FlickrFetcher 类中获取NSFetchedResultsController 的实用方法:

- (NSFetchedResultsController *)fetchedResultsControllerForEntity:(NSString*)entityName withPredicate:(NSPredicate*)predicate 
    NSFetchedResultsController *fetchedResultsController;

    /*
     Set up the fetched results controller.
     */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self managedObjectContext]];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Add a predicate if we're filtering by user name
    if (predicate) 
        [fetchRequest setPredicate:predicate];
    

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:@"Root"];

    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];

    return [fetchedResultsController autorelease];

我自己的NSFetchedResultsController 在我的UITableViewController 中创建:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:[flickFetcher managedObjectContext]];

    [request setEntity:entity];

    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:descriptor, nil];

    [request setSortDescriptors:sortDescriptors];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"person = %@", person];

    [request setPredicate:predicate];

    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[flickFetcher managedObjectContext] sectionNameKeyPath:nil cacheName:@"Root"];

    [request release];
    [descriptor release];
    [sortDescriptors release];

    NSError *error = nil;
    [fetchedResultsController autorelease];
    [fetchedResultsController performFetch:&error];

我看不出有什么区别。

【问题讨论】:

【参考方案1】:

不要随便看到任何东西。插入所有测试数据后,我想在上下文中插入保存。 (并且下次不要插入它。)

一条评论:

photo.person = person;
[person addPhotosObject:photo];

这是多余的。如果您设置另一个关系,则在核心数据中使用反向关系建模的关系将正确设置反向关系。因此,只需要其中一行。

【讨论】:

感谢我设法从上下文中检索照片的提示,这很奇怪,因为我所做的只是创建自己的获取结果控制器,它与我之前使用的实用方法没有什么不同,但现在表格单元格未设置,由于某种原因从未调用 cellForRowAtIndex,我将更新代码以显示两个 fetchedResultsControllers。 无 cellForRowAtIndex: = 无 tableView.dataSource,或 numberOfRowsInSection = 0 是 numberOfRowsInSection 交易,成功了。注意到我的 fetchedResultsControllers 有什么不同吗?除了升序参数

以上是关于在 Core Data 中获取具有关系的实体的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Core Data 中多个实体的属性获取属性值?

Core Data Fetch 在插入实体时保存关系(同时)

Core Data中设置实体间关系的原因

在 Core Data 中获取过滤的关系

iPhone Core Data - 访问具有多种关系的深层属性

如何从 Core Data 中的关系相关实体获取属性?