【问题标题】:Core Data : Insertion into One to Many Relationship核心数据:插入一对多关系
【发布时间】:2026-01-13 04:50:01
【问题描述】:

我刚刚开始学习如何在 iOS 上实现 Core Data Model。在一些关于如何在实体之间使用一对一关系存储和检索数据的基本教程之后,我现在正在尝试实现一对多关系。我的数据模型由两个实体组成,它们各自的类定义如下:

Restaurant:
@interface Restaurant :NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSMutableArray *user_reviews;   /* One to Many Relation to Review Entity*/
@end

Review:
@interface Review : NSObject
@property (nonatomic, strong) NSString *rating;
@property (nonatomic, strong) NSString *review_text;
@property (nonatomic, strong) User *user;
@end

我发现了使用 NSMutableSet 插入的类似问题,但我无法为 NSMutable Array 实现相同的问题。

目前我的插入代码如下所示:

NSManagedObjectContext *context = [self managedObjectContext];
Restaurant *rest = [NSEntityDescription insertNewObjectForEntityForName:@"Restaurant" inManagedObjectContext:context];
rest.name = restaurant.name;

我通过 JSON 检索 Restaurant 及其评论的数据,并将它们存储在临时类中,然后将它们保存到 CORE 数据库。 如何插入具有一对多关系的此类数据?

编辑: 目前我以将 user_review 属性定义为

的类的形式接收数据
NSMutableArray *user_reviews;

我正在尝试实现同一个类以插入核心数据模型。 但核心数据模型使用 NSSet 而不是 NSMutableArray。 一种粗暴的方法是复制所有具有相同属性的类,除了不使用 NSMutableArray,我将其更改为 NSSet。 但这会产生大量的冗余代码。难道不应该有更有效的方法吗?

【问题讨论】:

    标签: ios objective-c cocoa-touch core-data relational-database


    【解决方案1】:

    如果您的评论应该是您的 coreDataModel 中的关系,请使用 NSSet 代替 NSMutableArray 并将其与餐厅实体连接。

    回顾:

    在餐厅:

    如果你让 xcode 生成你的类,它会是这样的:

    Restaurant:
    @interface Restaurant : NSManagedObject
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, strong) NSSet *user_reviews;   /* One to Many Relation to Review Entity*/
    
    @interface Restaurant(CoreDataGeneratedAccessors)
    
    - (void)addUser_reviewsObject:(Review *)value;
    - (void)removeUser_reviewsObject:(Review *)value;
    - (void)addUser_reviews:(NSSet *)value;
    - (void)removeUser_reviews:(NSSet *)value;
    
    @end
    
    Review:
    @interface Review : NSManagedObject
    @property (nonatomic, strong) NSString *rating;
    @property (nonatomic, strong) NSString *review_text;
    @property (nonatomic, strong) User *user;
    @property (nonatomic, strong) Restaurant *restaurant;
    @end
    

    您的电话将是:

    NSManagedObjectContext *context = [self managedObjectContext];
    Restaurant *rest = [NSEntityDescription insertNewObjectForEntityForName:@"Restaurant" inManagedObjectContext:context];
    rest.name = restaurant.name;
    
    Review *rev = [NSEntityDescription insertNewObjectForEntityForName:@"Review" inManagedObjectContext:context];
    rev.rating = @"1";
    rev.review_text = @"nomnomnom";
    
    [rest addUser_reviewsObject:rev];
    // or rev.restaurant = restaurant; one of both is enought as far as I remember
    
    // save your context
    

    编辑

    如果它必须是NSMutableArray,则不能是一个理由。
    这些总是NSSets(如果 x 到 n)或目标类。使用NSMutableArray 可以利用集合和自动处理的优势。

    但如果你真的想存储在 NSMutableArray 中,我建议至少通过 reviewID 属性(唯一)扩展你的 Review 类并将 NSMutableArray 存储为 Transformable

    //Review:
    
    @interface Review : NSManagedObject
    @property (nonatomic, strong) NSString *rating;
    @property (nonatomic, strong) NSString *review_text;
    @property (nonatomic, strong) User *user;
    @property (nonatomic, strong) NSNumber *reviewID;
    @end
    
    //Restaurant.h:
    
    @interface Restaurant : NSManagedObject
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, strong) NSSet *user_reviews; // Set of NSNumbers
    
    - (void)addUser_reviewsObject:(Review *)value;
    - (void)addUser_reviewsID:(NSNumber *)value;
    - (void)removeUser_reviewsObject:(Review *)value;
    - (void)addUser_reviews:(NSMutableArray *)value;
    - (void)removeUser_reviews:(NSMutableArray *)value;
    
    @end
    
    //Restaurant.m:
    
    - (void)addUser_reviewsObject:(Review *)value
    {
        [self addUser_reviewsID:value.reviewID];
    }
    
    - (void)addUser_reviewsID:(NSNumber *)value
    {
        if(![self.user_reviews containsObject:value];
            [self.user_reviews addObject:value];
    }
    
    - (void)removeUser_reviewsObject:(NSNumber *)value
    {
        // follow upper logic and implement yourself
    }
    
    - (void)addUser_reviews:(NSMutableArray *)value
    {
        // follow upper logic and implement yourself
    }
    
    - (void)removeUser_reviews:(NSMutableArray *)value
    {
        // follow upper logic and implement yourself
    }
    

    【讨论】:

    • 对,只需在这部分复制/粘贴您的代码^^ 如果它们不是NSObjects 而是NSManagedObjects,有问题吗?如果有理由反对此解决方案,请告诉我:)
    • "... 据我记得" - 如果 Restaurant.user_reviews 和 Review.restaurant 设置为 ,那 正确的逆向关系,如屏幕截图所示。
    • 这就是问题所在。我首先在 RestKit 0.20 的帮助下从 API 在线加载整个数据。 Restkit 将所有关系加载到数组而不是 NSSet 中。我为“Restaurant.h”定义了一个类,供 Restkit 加载/映射数据。现在我正在尝试通过将数据加载到 Core Data Model 来存储数据,以便可以离线访问。但要做到这一点,我需要为每个实体创建类。我正在尝试重用我为 RestKit API 创建的类,因为除了 NSMutableArray 和 NSSet 之外,一切都是一样的。
    • @Kyuubi:您应该在问题中添加您正在使用 RestKit,因为这是相关信息。 - 我没有使用 RestKit 的经验,但从我所看到的(在 SO 中)来看,在我看来,您可以告诉 RestKit 关系,以便自动建立连接。
    • 如果它必须是一个 NSMutableArray,它不能是一个 ration。这些总是NSSets(如果 x 到 n)或目标类。使用NSMutableArray 可以利用集合和自动处理的优势。但是,如果您真的想存储在NSMutableArray 中,我建议您至少通过“reviewID”属性扩展您的Review 类并将NSMutableArray 存储为Transformable。我会将这部分添加到我的答案中
    【解决方案2】:
    Review *review = (Review *)[NSEntityDescription insertNewObjectForEntityForName:@"Review" inManagedObjectContext:[self managedObjectContext]];
    review.review_text = @"test text";
    //set other properties if needed
    
    rest.user_reviews = [NSSet setWithObjects:review, nil];//just make NSSet for you reviews
    

    【讨论】:

    • 这行不通。 Core Data 的多对多关系被建模为 NSSet,而不是 NS(Mutable)Array。