首页 文章

如何正确保存到coredata一对多的关系

提问于
浏览
3

我很擅长保存到coreData并使用iOS开发 .

What I am trying to achieve:

我希望能够在我的数据库中拥有一个具有唯一标识符/用 idFB 拉取的用户,并且该用户可以创建和检索他们的工作例程 .

How far have I gone?

我设法(我认为)创建了一个方法,可以正确地检索 Routine entityUser 相关联的 routineName . 请参阅 fetch 方法 .

My problem:

我想我没有与正确的实体关系协会保存 User (usersExercise) <--->> Routine (userID) . 顺便说一句,我认为我的 save 方法不正确...因为我将整个用户保存到userID,它只是感觉不对?主要是因为当它吐出 Routine.userID 时它会拉动整个关联用户而不是特定ID?我真的不知道会发生什么

有谁可以帮我正确构建这些方法?我对coreData保存和 Build 正确关系的整个过程非常困惑 .

enter image description here

- (void) save {
    Routine *newRoutine = [NSEntityDescription insertNewObjectForEntityForName:@"Routine" inManagedObjectContext:context];

    newRoutine.users = [self getCurrentUser];
    newRoutine.routineName = @"myRoutine Test Name";
    NSError* error;
    [context save:&error ];

    NSLog(@"Saved now try to fetch");
    [self fetch];

}
-(void) fetch {
    NSFetchRequest *fetchRequestItems = [[NSFetchRequest alloc] init];
    NSEntityDescription *entityItem = [NSEntityDescription entityForName:@"Routine" inManagedObjectContext:context];
    [fetchRequestItems setEntity:entityItem];
    User* user = [self getCurrentUser];
    // if i try [[self getCurrentUser] usersRoutine] it shows an error

    [fetchRequestItems setPredicate:[NSPredicate predicateWithFormat:@"users == %@",user]];

    //Sort by last edit ordered
    NSArray *sortDescriptors = [NSArray arrayWithObjects:nil];
    [fetchRequestItems setSortDescriptors:sortDescriptors];
    NSError *error = nil;
    NSArray* Routines = [context executeFetchRequest:fetchRequestItems error:&error];
    NSLog(@"result %@", [(Routine *)Routines[0] users]  );


}
-(User *)getCurrentUser {
    NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDesc];

    if (_appDelegate.isFB)
    { 
        request.predicate = [NSPredicate predicateWithFormat:@"idFB LIKE %@",_appDelegate.fdID];
        NSError *error = nil;
        NSArray *matches = [[context executeFetchRequest:request error:&error] mutableCopy];

        return (User *)matches[0];
    } else
    {
        NSLog(@"CreateRoutinePOPUP NON FB TO BE TESTED");
        request.predicate = [NSPredicate predicateWithFormat:@"email LIKE %@",_appDelegate.currentUser];
        NSError *error = nil;
        NSArray *matches = [[context executeFetchRequest:request error:&error] mutableCopy];

        return (User *)matches[0];
    }

这是获取中的NSLog正在打印的内容:

2013-04-28 22:33:26.555 iGym[7916:c07] result <User: 0xa480580> (entity: User; id: 0xa495a00 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/User/p1> ; data: {
    dob = "1986-12-26 00:00:00 +0000";
    email = ".com";
    firstTime = nil;
    gender = male;
    height = nil;
    idFB =3333;
    idUserExternal = 0;
    idUserInternal = 0;
    isPT = nil;
    language = "en_US";
    location = "London, United Kingdom";
    metricSystem = nil;
    name = Joan;
    nickname = nil;
    password = nil;
    surname = Thurft;
    usersExercise = "<relationship fault: 0xa4824a0 'usersExercise'>";
    usersRoutine =     (
        "0xa495f00 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p6>",
        "0xa4877e0 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p1>",
        "0xa4877f0 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p2>",
        "0xa487800 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p3>",
        "0xa487810 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p4>",
        "0xa487820 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p5>"
    );
    weight = nil;
})

当我添加NSLog时(@“获取当前结果%@”,[(User *)匹配[0] usersRoutine]);到getCurrentUser方法,我得到整个用户的数据和关系说

usersExercise = "<relationship fault: 0xa464730 'usersExercise'>";

2 回答

  • 7

    您需要使用提供的方法在一对多对象中添加"many object" . 在你的情况下,它被称为 addRoutineObject:

    试试这个新的保存方法:

    - (void) save {
    
        Routine *newRoutine = [NSEntityDescription insertNewObjectForEntityForName:@"Routine" inManagedObjectContext:context];
        newRoutine.routineName = @"myRoutine Test Name";
    
        NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        [request setEntity:entityDesc];
    
    
        NSArray *matches;
        NSError *error = nil;
        if (_appDelegate.isFB)
        { 
            request.predicate = [NSPredicate predicateWithFormat:@"idFB LIKE %@",_appDelegate.fdID];
            matches = [[context executeFetchRequest:request error:&error] mutableCopy];
    
        } else
        {
            NSLog(@"CreateRoutinePOPUP NON FB TO BE TESTED");
            request.predicate = [NSPredicate predicateWithFormat:@"email LIKE %@",_appDelegate.currentUser];
            matches = [[context executeFetchRequest:request error:&error] mutableCopy];
        }
    
        if (matches.count == 0)
        {
            NSLog(@"no user matched");
        }
        else
        {
            User *aUser = [matches objectAtIndex:0];
            [aUser addRoutineObject:newRoutine];
            if (![context save:&error])
            {
                NSLog(@"couldn't save: %@", [error localizedDescription]);
            }
        }
       }
    
  • 0

    核心数据与使用标准数据库完全不同,在这个数据库中,您将一些外键(如 userID )分配给另一个表,您希望与 User 对象 Build 关系,然后使用该外来ID来查找 exercise.where('user_id = ?', userID) 之类的关系 . 相反,您可以定义实际关系,并让Core Data处理幕后的所有内容,以设置任何连接表或外键 .

    而不是如何设置它,你只需在 User 实体中有两个关系 exercisesroutines 映射到 ExerciseRoutine 实体然后你在 ExerciseRoutine 上有一个反向关系,称为 users 如果这是一种拥有和属于多对的关系 . 现在,您需要将 usersExercise 替换为 exercisesusersRoutine 替换为 routines ,然后将 userID 替换为 users ,用于 ExerciseRoutine 实体 .

    即使你实际上并不需要这种反向关系,你仍然需要它,因为Core Data将它用于数据完整性目的,如果你让它无人居住,Xcode会给你一个警告 .

    当您设置这些关系时,您将调用例如 user.exercises 的例程或练习,它将返回该用户的相关练习集 . 正如您所注意到的,Core Data将返回他们称之为 fault 的关系,这种关系将被触发,并且当您确实需要该关系的内容时返回数据 . 存在故障,因此您只需返回所需的信息,而不是在数据集上运行不必要的查询 .

    另外需要注意的是,Core Data并不像你正在做的那样 userID . 相反,核心数据中的每个对象都有一个由 [objectName objectID] 找到的唯一ID(除了特殊情况之外,它只需要设置一个唯一ID作为实体的属性 .

    此外,你真的不需要像在多线程应用程序中那样使用那些独特的传递对象进行后台处理,在这种情况下 NSManagedObjectID 是线程安全的,你可以使用它在后台线程上再次查找对象/托管对象上下文 .

    我真的建议您阅读核心数据的简介,例如http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started

    如果您习惯于正常的数据库设置/架构,首次转换为Core Data可能有点奇怪,但是一旦习惯了它,它实际上要快得多,并为您处理幕后的所有艰苦工作 .


    评论更新:

    你're misunderstanding the concept of relationships in Core Data. In Core Data, a relationship does not return an associated ID like a typical database join relationship would. Instead, it returns a fault which gets fired when you need the data from that relationship. So it'没有返回整个 User 对象,而是 fault 到关联的 User 对象,当你做 exercise.user.name 这样的事情时会被触发和查询

    你的代码的工作方式与保存时的代码完全相同,你只是在不正确的假设下 .

相关问题