RestKit 0.20.1 复合键和嵌套关系

Posted

技术标签:

【中文标题】RestKit 0.20.1 复合键和嵌套关系【英文标题】:RestKit 0.20.1 Composite keys and nested relationships 【发布时间】:2013-05-31 13:16:01 【问题描述】:

我正在使用 RestKit 0.20.1 将 XML 提要映射到核心数据模型。它们如下:

XML 提要

<?xml version="1.0" encoding="utf-8"?>
<payload>
    <competitions>
        <competition id="100" name="Comp A" />
        <competition id="200" name="Comp B" />
        <competition id="300" name="Comp C" />
        <competition id="400" name="Comp D" />
    </competitions>
    <seasons>
        <season id="10" span="2008/09"/>
        <season id="20" span="2009/10"/>
        <season id="30" span="2010/11"/>
        <season id="40" span="2011/12"/>
        <season id="50" span="2012/13"/>
    </seasons>
    <players>
        <player id="1" name="Justyn Spooner">
            <season id="10">
                <playerstats competitionID="100" goals="0" played="0" />
                <playerstats competitionID="200" goals="5" played="4" />
                <playerstats competitionID="300" goals="2" played="1" />
            </season>
            <season id="20">
                <playerstats competitionID="300" goals="1" played="4" />
                <playerstats competitionID="400" goals="2" played="9" />
            </season>
        </player>
    </players>
</payload>

核心数据模型

到目前为止,我已经设置了实体映射和响应描述符,但不确定如何设置它们之间的关系。

实体映射

RKEntityMapping *playerMapping = [RKEntityMapping mappingForEntityForName:@"Player" inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
playerMapping.identificationAttributes = @[@"attID"];
[playerMapping addAttributeMappingsFromDictionary:@
    @"id"   : @"attID",
    @"name" : @"attName"
];

RKEntityMapping *competitionMapping = [RKEntityMapping mappingForEntityForName:@"Competition" inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
competitionMapping.identificationAttributes = @[@"attID"];
[competitionMapping addAttributeMappingsFromDictionary:@
    @"id"   : @"attID",
    @"name" : @"attName"
];

RKEntityMapping *seasonMapping = [RKEntityMapping mappingForEntityForName:@"Season" inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
seasonMapping.identificationAttributes = @[@"attID"];
[seasonMapping addAttributeMappingsFromDictionary:@
    @"id"   : @"attID",
    @"span" : @"attYearSpan"
];

RKEntityMapping *playerStatsMapping = [RKEntityMapping mappingForEntityForName:@"PlayerStats" inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
playerStatsMapping.identificationAttributes = @[@"attFKCompetitionID", @"attFKSeasonID", @"attFKPlayerID"];
[playerStatsMapping addAttributeMappingsFromDictionary:@
    @"competitionID" : @"attFKCompetitionID",
    @"????"          : @"attFKSeasonID",
    @"????"          : @"attFKPlayerID",
    @"goals"         : @"attGoals",
    @"played"        : @"attGamesPlayed"
];

响应描述符

RKResponseDescriptor *playerResponseDescriptor =        [RKResponseDescriptor responseDescriptorWithMapping:playerMapping       pathPattern:kURLBasePath@"/players" keyPath:@"payload.players.player"                       statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKResponseDescriptor *seasonResponseDescriptor =        [RKResponseDescriptor responseDescriptorWithMapping:seasonMapping       pathPattern:kURLBasePath@"/players" keyPath:@"payload.seasons.season"                       statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKResponseDescriptor *competitionResponseDescriptor =   [RKResponseDescriptor responseDescriptorWithMapping:competitionMapping  pathPattern:kURLBasePath@"/players" keyPath:@"payload.competitions.competition"             statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKResponseDescriptor *playerStatsResponseDescriptor =   [RKResponseDescriptor responseDescriptorWithMapping:playerStatsMapping  pathPattern:kURLBasePath@"/players" keyPath:@"payload.players.player.season.playerstats"    statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

除了缺少的关系之外,您会注意到在 playerStatsMapping 中我需要添加一个由 Player、Season 和 Competition 三个主键组成的 IdentificationAttribute。比赛 ID 很容易映射,因为它直接位于 keyPath payload.players.player.season.playerstats(在 playerStatsResponseDescriptor 中定义)下。问题是我不知道如何引用playerStatMapping中的parent.idparent.parent.id分别映射到attFKSeasonID和attFKPlayerID。

我不认为 RestKit 支持访问 entityMappings 中的父 keyPath,我确定可能有另一种解决方法?这张图显示了我想要提取的内容:

在伪代码中,如果我不使用 RestKit,这就是我想要做的:

For each player in the XML response:

    find out if that player exists in Core Data; create if not
    keep it around in a local variable
    for each season under the player in the XML:
    
        create if needed; keep around.
        for each competition under the season in the XML:
        
            create if needed; keep around.
            Take the current player, season and competition. 
            Is there a PlayerStat matching those three things? Create if not
            Set that player stat's attGoals and attGamesPlayed to the values that are mapped from goals and played in the XML
        
    

所以这里基本上有两个问题:

    您将如何设置关系映射? 在构造playerStatsMapping 时如何映射playerseason id,以便playerStatsMapping 可以将它们用作identificationAttributes

任何帮助将不胜感激。

谢谢, 贾斯汀

【问题讨论】:

一旦建立了关系,你真的需要ID吗?使用关系,您可以导航到关系目标对象的统计信息或谓词搜索。这对你有用吗? @Wain 感谢您的快速回复。关系可能会解决它。我已经更新了问题以使其更清楚。我目前无法识别个人playerstat,因为它没有自己的 ID。我希望从它引用的比赛及其父母(球员和赛季)中产生这个。这三个组合键应该允许为 playerStats 条目创建唯一键。我这样做是因为我认为 RestKit 需要一个映射来设置一个 IdentificationAttribute 以便它能够检测和更新现有条目而不是创建一个新条目? 没错,identificationAttribute 很重要。标识的最佳选择可能是在托管对象子类中实现“willSave”,并通过询问关系在其中生成值。我认为在映射过程中没有办法向后导航。可能是在映射过程中尝试编辑映射变量(我之前没有尝试过)。 好的,我会继续玩它,如果我知道如何做到这一点,我会回帖。如果没有其他方法,“willSave”选项可能是一个很好的后备方案。谢谢。 我可能应该将其拆分为单独的问题,但您将如何为该映射创建关系? 【参考方案1】:

简而言之,RestKit 现在支持 @parent@root 映射键作为 development branch 的一部分。这允许访问当前映射对象的父节点,如果它被映射为其父实体的关系。

这和我遇到的另一个问题非常相似,如果需要,我可以更详细地提供上述具体案例的答案,否则请查看this answer。

【讨论】:

以上是关于RestKit 0.20.1 复合键和嵌套关系的主要内容,如果未能解决你的问题,请参考以下文章

主键和外键的复合键不能建立关系

Restkit:嵌套关系映射

RestKit 对象映射与外键和服务

RestKit .22:无法成功映射与嵌套 JSON 的关系

Restkit 在嵌套的外键关系中使用 @parent

在复合键和外键之间创建关系