Justyn
Justyn

Reputation: 1500

RestKit 0.20.1 Composite keys and nested relationships

I am using RestKit 0.20.1 to map an XML feed to a Core Data Model. These are as follows:

XML Feed

<?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>

Core Data Model

Core Data Model

So far I have the entity mappings setup and the response descriptors configured but am not sure how to setup the relationships between them.

Entity Mapping

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"
}];

Response Descriptors

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)];

Aside from the missing relationships, you'll notice that in the playerStatsMapping I need to add an identificationAttribute that is made up of the three primary keys of Player, Season and Competition. The competition id is easily mapped as it is directly under the keyPath payload.players.player.season.playerstats (defined in the playerStatsResponseDescriptor). The problem is that I don't know how to reference the parent.id and parent.parent.id from the playerStatMapping to map to the attFKSeasonID and attFKPlayerID respectively.

I don't think RestKit support accessing a parent keyPath in the entityMappings and I'm sure there is probably another way around this? This diagram show what I want to pull out:

XML Mapping

In pseudo code, this is what I would be wanting to do if I wasn't using 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
        }
    }
}

So there are essentially two questions here:

  1. How would you setup the relationship mappings?
  2. How would you map the player and season ids when constructing the playerStatsMapping so that the playerStatsMapping can use them as the identificationAttributes?

Any help would be greatly appreciated.

Thanks, Justyn

Upvotes: 1

Views: 711

Answers (1)

Justyn
Justyn

Reputation: 1500

In short, RestKit now supports the @parent and @root mapping keys as part of the development branch. This allows access to the parent nodes of the currently mapped object IF it is being mapped as a relationship of its parent entity.

This is very similar to another issue I had, I can provide an answer to the specific case above in more detail if required, otherwise please take a look at this answer.

Upvotes: 1

Related Questions