9

Setup

Imagine the following relationship between an Author and a Book:

[Author] -- has many --> [Book]

Using restkit, I have an Author model and a Book model, and I create the relationship between Author and Book like this:

[authorMapping hasMany:@"books" withMapping:booksMapping];

I can now access an Author's books through Author's property:

@property (strong, nonatomic) NSSet *books;

So far so good. Similarly, I'd like to access a Book's author through it's property:

@property (weak, nonatomic) Author *author;

Problem

This is where the problems start. To achieve this inverse relationship, I added the following:

[booksMapping hasOne:@"author" withMapping:authorMapping];

This results in each mapping recursively calling each other until the program dies. Not good at all. Inspecting the docs I find that hasOne/Many:withMapping: methods are simply calling mapKeyPath:toRelationShip:withMapping: so there's not really an alternative there. Furthermore, adding a mapping as the following:

[bookMapping mapKeyPath:@"author" toAttribute:@"author"];

Will, obviously, just create the mapping but not actually map the Author object to the Book's author property.


Question

How can I create an inverse one-to-many relationship between two or more models using RestKit, but not CoreData?

Kasper Munck
  • 4,173
  • 2
  • 27
  • 50
  • Muncken, is there a specific reason you do not want to use Core Data? I have found that Core Data is well worth the initial learning curve, and it makes object relationship mapping quite simple. – Scott Lieberman Jan 08 '13 at 15:03
  • The data loaded changes all the time so I have no reason to persist it (the author->book case is just a simplified example to illustrate the problem). Furthermore, I find that coredata complicates testing significantly so I defided that using it would cause more bad than good (I did, however, find Graham Lee's blog post http://bit.ly/UNzKFL , that helps solve the testing problem, later on). – Kasper Munck Jan 10 '13 at 16:22

2 Answers2

2

Note: newer versions of restkit use a diffent mapping scheme.

Note2: I think in your example you mean:

[booksMapping hasOne:@"author" withMapping: authorMapping]; (not booksMapping)

The problem here is not the mapping, you shouldn't define the same mapping to the many-to-one side, this mapping is already done (defined in the authorMapping). You simply want a pointer to the parent item, not to repeat the whole mapping process.
The real problem is you'd need to define the parent object as a property of the child object, in terms of NSDictionaries, this might be possible using a custom category, but it's not something RestKit supports to be used to transformed objects.

Kevin R
  • 8,230
  • 4
  • 41
  • 46
  • Thanks for the answer Kevin. I ended up using another solution which I will submit in a moment. Btw, there's a great post related to your link on NSHipster: http://nshipster.com/kvc-collection-operators/ – Kasper Munck Feb 12 '13 at 19:56
0

My solution is specific to my project, but might be suitable for others as well. I added a loadBooks method to my Author model, which fetches all its books from the api. The trick here was to run through all the loaded Book objects and set their Author property to self. Something like this:

Author.m

- (void)loadBooksWithCompletionBlock..... {
    ...
    for (Book *book in result) {
        book.author = self;
    }
    ...
} 

I am not sure whether I am completely satisfied with this approach, but it suits the needs of this particular situation.

Another thing that I was not aware of at the time of writing my question, was the exact response from the API (woops). It turns out that an Author object in the API response knows nothing about its books. On the other hand, a Book object in the API response always knows its Author. Getting all books of an Author would require a call similar to /api/books/<author_id>, which is the endpoint I use in the loadBooks... method. Hence, it's slightly more complicated to create the inverse-one-to-many relationship that I sought an answer for.

RestKit update

It should be noted that I, in the mentioned application, am not using the newest version of RestKit. During the development of the app RestKit released a major updated, which changed the ways several things are done. This question refers to versions of RestKit < 0.2.

Kasper Munck
  • 4,173
  • 2
  • 27
  • 50