0

I'm using RestKit and I cannot figure out the way to make the mapping work. I have a Playlist Managed Object which has many Beat Managed Objects.

let playlistMapping = RKEntityMapping(forEntityForName: "Playlist", inManagedObjectStore: appDelegate.managedObjectStore)
playlistMapping.identificationAttributes = ["playlistId"]
playlistMapping.addAttributeMappingsFromDictionary(["id" : "playlistId", "name" : "name", "beats" : "beatIds"])

let beatMapping = RKEntityMapping(forEntityForName: "Beat", inManagedObjectStore: appDelegate.managedObjectStore)
beatMapping.identificationAttributes = ["beatId"]
beatMapping.addAttributeMappingsFromDictionary(["id" : "beatId", "name" : "name"])

playlistMapping.addConnectionForRelationship("playlistBeats", connectedBy: ["beatIds" : "beatId"])

let statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
let playlistResponseDescriptor = RKResponseDescriptor(mapping: playlistMapping, method: RKRequestMethod.Any, pathPattern: "/playlists/:id", keyPath: "playlist", statusCodes: statusCodes)

let beatResponseDescriptor = RKResponseDescriptor(mapping: beatMapping, method: RKRequestMethod.Any, pathPattern: "/beats/:id", keyPath: "beats", statusCodes: statusCodes)

Here's the JSON

{
    "playlist": {
        "id": "top-rated",
        "beats": [
            "180574",
            "181515"
        ]
    },
    "beats": [
        {
            "id": "180574",
            "producer": "14649",
            "name": "On The Hunt"

        },
        {
            "id": "181515",
            "producer": "14649",
            "name": "Anatomy"
        }
    ]
}

Here are the Managed Objects

@interface Playlist : NSManagedObject

@property (nonatomic, retain) NSString * playlistId;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) id beatIds;
@property (nonatomic, retain) NSSet *playlistBeats;
@end


@interface Beat : NSManagedObject

@property (nonatomic, retain) NSNumber * beatId;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) Producer *producer;
@end

When I run this I get the error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Cannot connect relationship: invalid attributes given for source entity 'Playlist': beats'

EDIT:

I have already read this answer: Foreign key relationship mapping with RestKit but I do not understand how to make it work for my particular JSON data.

I already have a NSSet *beats attribute in the Playlist Managed Object.

Where in the issue in the other question they have single Team for each User - I have multiple Beats for each Playlist.

EDIT 2:

Ok I've added a transient attribute beatIds in the Playlist entity which is of Transformable type. I've mapped it to hold the array of beat id's in the playlist object. Now the app doesn't crash any more but I don't think it's processing the relationship correctly.

<Playlist: 0x10dae81b0> (entity: Playlist; id: 0xd000000000040000 <x-coredata://F9813F68-CBAD-4947-81B5-C126E3BF33D9/Playlist/p1> ; data: {
    beatIds = nil;
    name = nil;
    playlistBeats = "<relationship fault: 0x10dae6f10 'playlistBeats'>";
    playlistId = "top-rated";
})
Community
  • 1
  • 1
Wasim
  • 4,953
  • 10
  • 52
  • 87
  • Have you checked whether the JSON `beats` collection is being built as a `NSSet` or `NSArray`? – Jeff Wolski Jun 24 '14 at 00:21
  • If i'm understanding you correctly then the `beats` collection is an `NSSet` as defined in the `Playlist : NSManagedObject` code above. Is this what you mean? – Wasim Jun 24 '14 at 07:15
  • You are missing the transient (on Playlist) which holds the ids to map. In the other answer it is a single item, in your case it is an array. Other than that the process is the same. – Wain Jun 25 '14 at 07:31
  • @Wain please see edit, i've added a transient on the `Playlist` object called `beatsIds` and mapped it to the `beats` array in the JSON data. This still doesn't seem to be making the relationship correctly. I've edited the code above, appreciate your help. – Wasim Jun 25 '14 at 20:10
  • You want the property to be an `NSArray`. Have you tested accessing the relationship and looked at the mapping trace log? – Wain Jun 26 '14 at 07:16
  • @Wain it appears to be working but only when I request it a second time. Within the block `operation.setCompletionBlockWithSuccess({ (operation: RKObjectRequestOperation!, result: RKMappingResult!) in` I locate the `Playlist` object and try to access it's `playlistBeats` property. It's a relationship error on the first operation run, but if I run the operation again it contains all the `Beat` objects. Why would it do that? – Wasim Jun 28 '14 at 07:33
  • You access the mapping result to check this? It shouldn't. The server result could be wrong, or you could be accessing a disconnected context, hard to know - now you have resolved the foreign key mapping you should probably create a new question for other issues and show the incoming data and mapping results... – Wain Jun 28 '14 at 08:47

0 Answers0