Restkit - 删除具有相同 URL 路径的孤立对象

Posted

技术标签:

【中文标题】Restkit - 删除具有相同 URL 路径的孤立对象【英文标题】:Restkit - Deleting orphaned objects with the same URL path 【发布时间】:2014-08-05 07:13:26 【问题描述】:

我已阅读此文档,但它没有显示此问题的任何示例解决方案: RKManagedObjectRequestOperation Class Reference

我想使用几个 addFetchRequestBlock 方法从我正在进行的同一个 API 调用中删除孤立对象。当我在服务器端删除一些记录时,父对象工作正常。但是,Restkit 不会删除那些嵌套对象。


我的 API JSON 输出 - /regions :

(该地区有许多地区和建筑物)

(区有很多建筑物)


"regions": [
    
        "id": 1,
        "name": "region A",
        "districts": [
            
                "id": 1,
                "region_id": 1,
                "name": "district A",
                "buildings": [
                    
                        "id": 1,
                        "region_id": 1,
                        "district_id": 1,
                        "name": "building A"
                    ,
                    
                        "id": 2,
                        "region_id": 1,
                        "district_id": 1,
                        "name": "building B"
                    
                ]
            ,
            
                "id": 2,
                "region_id": 1,
                "name": "district B",
                "buildings": []
            ,
            
                "id": 3,
                "region_id": 1,
                "name": "district C",
                "buildings": []
            
        ]
    ,
    
        "id": 2,
        "name": "region B",
        "districts": [
            
                "id": 4,
                "region_id": 2,
                "name": "district D",
                "buildings": [
                    
                        "id": 3,
                        "region_id": 2,
                        "district_id": 4,
                        "name": "building C"
                    
                ]
            ,
            
                "id": 2,
                "region_id": 1,
                "name": "district E",
                "buildings": []
            
        ]
    
]


我的核心数据模型:


我的对象映射和 addFetchRequestBlock:

(我正在尝试使用 3 addFetchRequestBlock 来删除孤立对象;调用 URL 路径时的 Region、District 和 Building)

(1、Restkit正确删除了那些孤立的Region对象)

(2. District和Building中被删除的对象还在客户端)

- (void) setupRegionMappings


// Object Mappings
// -------------------------------------------------
// Get RKObjectManager singleton
RKObjectManager *manager = [RKObjectManager sharedManager];



// Get default managed object store
RKManagedObjectStore *managedObjectStore = [RKManagedObjectStore defaultStore];

// Create the RKObjectMapping mapping for our object class:
RKEntityMapping *buildingMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([Building class])
                                                  inManagedObjectStore:managedObjectStore];



[buildingMapping addAttributeMappingsFromDictionary:@
                                                 @"id": @"buildingID",
                                                 @"district_id": @"districtID",
                                                 @"region_id": @"regionID",
                                                 @"name": @"name",
                                                 @"name_zh": @"nameZh",
                                                 @"name_cn": @"nameCn",
                                                 @"name_en": @"nameEn"
                                                 ];

// Identify the object in database
buildingMapping.identificationAttributes = @[@"buildingID"];


// Establish the connection for relation between attributes in core data
[buildingMapping addConnectionForRelationship:@"region" connectedBy:@@"regionID": @"regionID"];
[buildingMapping addConnectionForRelationship:@"district" connectedBy:@@"districtID": @"districtID"];
[buildingMapping addConnectionForRelationship:@"shops" connectedBy:@@"buildingID": @"buildingID"];



// Create the RKObjectMapping mapping for our object class:
RKEntityMapping *districtMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([District class])
                                                  inManagedObjectStore:managedObjectStore];



[districtMapping addAttributeMappingsFromDictionary:@
                                                 @"id": @"districtID",
                                                 @"region_id": @"regionID",
                                                 @"name": @"name",
                                                 @"name_zh": @"nameZh",
                                                 @"name_cn": @"nameCn",
                                                 @"name_en": @"nameEn"
                                                 ];

// Identify the object in database
districtMapping.identificationAttributes = @[@"districtID"];


// Establish the connection for relation between attributes in core data
[districtMapping addConnectionForRelationship:@"region" connectedBy:@@"regionID": @"regionID"];
[districtMapping addConnectionForRelationship:@"buildings" connectedBy:@@"districtID": @"districtID"];
[districtMapping addConnectionForRelationship:@"shops" connectedBy:@@"districtID": @"districtID"];


// Define the relationship mapping on json
[districtMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"buildings"
                                                                                toKeyPath:@"buildings"
                                                                              withMapping:buildingMapping]];


// Create the RKObjectMapping mapping for our object class:
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([Region class])
                                               inManagedObjectStore:managedObjectStore];
[mapping addAttributeMappingsFromDictionary:@
                                              @"id": @"regionID",
                                              @"name": @"name",
                                              @"name_zh": @"nameZh",
                                              @"name_cn": @"nameCn",
                                              @"name_en": @"nameEn"
                                              ];
// Identify the object in database
mapping.identificationAttributes = @[@"regionID"];

// Establish the connection for relation between attributes in core data
[mapping addConnectionForRelationship:@"districts" connectedBy:@@"regionID": @"regionID"];
[mapping addConnectionForRelationship:@"buildings" connectedBy:@@"regionID": @"regionID"];
[mapping addConnectionForRelationship:@"shops" connectedBy:@@"regionID": @"regionID"];

// Define the relationship mapping on json
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"districts"
                                                                        toKeyPath:@"districts"
                                                                      withMapping:districtMapping]];




// The mapping will be triggered if a response status code is anything in 2xx
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);

// Put it all together in response descriptor (for a GET request method)
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
                                                                                        method:RKRequestMethodGET
                                                                                   pathPattern:@"regions"
                                                                                       keyPath:@"regions"
                                                                                   statusCodes:statusCodes];


// Add response descriptor to our shared manager
[manager addResponseDescriptor:responseDescriptor];





// Routings
// -------------------------------------------------
// Route for list of type objects
RKRoute *indexRoute = [RKRoute routeWithName:@"regions" pathPattern:@"regions" method:RKRequestMethodGET];
indexRoute.shouldEscapePath = YES;


// Add defined routes to the Object Manager router
[manager.router.routeSet addRoutes:@[indexRoute]];



// Making Consistency
// -------------------------------------------------
// Deleting orphaned objects
// Define Fetch request to trigger on specific url
[manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) 

    // Create a path matcher
    RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"regions"];

    // Dictionary to store request arguments
    NSDictionary *argsDict = nil;

    // Match the URL with pathMatcher and retrieve arguments
    BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];


    // If url matched, create NSFetchRequest
    if (match) 
        NSFetchRequest *fetchRequest = [Region MR_requestAllSortedBy:@"regionID" ascending:YES];
        return fetchRequest;
    

    return nil;
];


[manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) 

    // Create a path matcher
    RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"regions"];

    // Dictionary to store request arguments
    NSDictionary *argsDict = nil;

    // Match the URL with pathMatcher and retrieve arguments
    BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];

    // If url matched, create NSFetchRequest
    if (match) 
        NSFetchRequest *fetchRequest = [District MR_requestAllSortedBy:@"districtID" ascending:YES];
        return fetchRequest;
    

    return nil;
];


[manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) 
    // Create a path matcher
    RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"regions"];

    // Dictionary to store request arguments
    NSDictionary *argsDict = nil;

    // Match the URL with pathMatcher and retrieve arguments
    BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];

    // If url matched, create NSFetchRequest
    if (match) 
        NSFetchRequest *fetchRequest = [Building MR_requestAllSortedBy:@"buildingID" ascending:YES];
        return fetchRequest;
    

    return nil;
];



当我进行一次相同的 API 调用时,如何同步这些嵌套实体? 非常感谢!

【问题讨论】:

【参考方案1】:

只会使用一个获取请求块。解决您的问题的正确方法是对您的关系使用 Core Data 删除规则,这样删除 Region 会导致 cascade 删除关联的 Districts 和 Buildings。

您在问题中显示的获取请求块会删除上次请求中未收到的所有内容。因为您正在使用 identificationAttributes 和 1:many 关系,所以在删除 Region 之前,接收到的响应可能会将现有的 Districts 和 Buildings 重新连接到新的 Region,因此级联不会适用于他们。

【讨论】:

【参考方案2】:

在我删除那些 addConnectionForRelationship 函数之后。它工作得很好......

【讨论】:

删除 addConnectionForRelationship 只是意味着您没有连接关系,它不会从数据存储中删除任何内容。

以上是关于Restkit - 删除具有相同 URL 路径的孤立对象的主要内容,如果未能解决你的问题,请参考以下文章

RestKit / CoreData:两次请求相同的URL时插入重复的对象而不是合并

具有相同元素和属性名称的 RestKit XML 映射

RESTKit:BaseURL 和路径模式

需要使用 RestKit 创建多个相同的实体

RestKit getObjectsAtURL?

使用 RESTKit 将 url 参数映射到对象