Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

Many to many relationship with the use of a lookup entity

TonyTony Posts: 12Registered Users
Hi Guys,

I'm hoping you can help me sort out an issue I'm experiencing with retrieving data from a entity via a relationship. I'll start off by explaining the relationships between the entities I'm currently working with:

I'm working with 4 Entities, named the following: Sections, Routes, SectionRoutes, and Grades.

The relationships between these entities are as follows:

Sections has a one-to-many relationship with SectionRoutes.
Routes has a one-to-many relationship with SectionRoutes.
Grades has a one-to-one relationship with Routes.

So the end goal which has resulted in the above design is as follows: One section can have many routes, and one route can be in many sections. So what I've done is I've created a lookup table that stores a section and a route to relate the two (namely SectionRoutes). So in my app I'm retrieving a list of routes from a web service that I'm then inserting into my model that will be associated to a section - this is all done on a separate thread in it's own NSManagedObjectContext so as to not block the main thread. So when inserting a new route, I already know which section it should belong to so I simply populate the Route properties as necessary, I then insert a new record into the SectionRoutes entity and add my new route and section NSManagedObjects. In the same method I also need to relate a Grade to the route I'm inserting. The web service returns a Grade ID which I use in an NSPredicate to retrieve the correct Grade from my local model (the Grades entity at this point is already populated). I then assign the Grade I've retrieved to my grade relationship for the new route. Once this is all complete, I then run a query to retrieve all the SectionRoute objects into a NSFetchedResultsController so as to populate a tableView to display all these routes.

Here is the code which creates a new route as described above:


Routes *newRoute = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:moc];

newRoute.name = name;

newRoute.rating = rating;

newRoute.height = height;

// this is where I grab the Grade NSManagedObject for the given grade ID that I get from the web service
Grades *grade = [Grades getGradeForGradeServerID:gradeID moc:moc];

// this outputs the correct value
NSLog(@\"colour == %@\", grade.colour);

// this is where I associate the returned grade to the new route I'm creating (one to one relationship)
newRoute.grade = grade;

// I then retrieve the section this route belongs to using the NSManagedObject ObjectID passed to this worker thread
Sections *parentSection = (Sections*)[moc objectWithID:sectionObjectID];

// insert this new route with it's parent section into the lookup table
SectionRoutes *sectionRouteObj = [SectionRoutes insertSectionWithRoute:parentSectionObj route:newRoute moc:moc];

[newRoute addSectionsObject:sectionRouteObj];

return newRoute;


So now onto my problem, I'm retrieving all the SectionRoutes and populating a tableView with routes for a given section. In my cellForRowAtIndexPath: I retrieve the SectionRoute for the given indexPath - I then extract the route which is related to my Routes entity to populate labels etc, I then also try extract the Route grade by doing the following: sectionRoute.route.grade. For some reason this is returning (null). I'm certain that when I associate a grade to a route (in my code above) that the grade itself is returned correctly from the local model, but for some reason when I try access it via the Route object as described it returns a null.

This is what the code in my cellForRowAtIndexPath: method that I'm using to retrieve the data I need looks like:


SectionRoutes *sectionRoute = [_sectionRoutesFetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:[indexPath row] inSection:0]];

Routes *route = sectionRoute.route;

[routeCustomCell.routeNameLbl setText:route.name];

[routeCustomCell.gradeLbl setText:[NSString stringWithFormat:@\"Grade: %@\", route.flexiGradeName]];

Grades *routeGrade = sectionRoute.route.grade;

// the three NSLogs below output null
NSLog(@\"routeGrade == %@\", routeGrade);

NSLog(@\"grade == %@\", routeGrade.name);

NSLog(@\"colour == %@\", routeGrade.colour);


Have I gone about associating a Grade to a Route in the wrong way? I'm not entirely sure why I'm getting a null when I try access the Grade of a Route.

Many thanks for the help!

Tony
Post edited by Tony on

Replies

  • FstuffFstuff Posts: 154Registered Users
    Grades has a one-to-one relationship with Routes.
    This seems like a possible explanation for what you are seeing. If each Route has a pointer to a Grade, but you then point a different Route to the same Grade, the first Route will then point to nil. That sounds wordy, perhaps a pseduocode explanation will illuminate:
    Route *a = ...;
    Route *b = ...;
    Grade *X = ...;

    a.grade = X; // a.grade == X, b.grade == nil
    b.grade = X; // a.grade == nil, b.grade == X
    So, I would first check to make sure that your Core Data schema matches the web service schema (i.e., your web service enforces the 1:1 relationship b/w Route and Grade). Then I would check that you are implementing this correctly when creating your Core Data objects (e.g., that you aren't recycling the same Grade object when parsing the data you receive, etc).

    Good luck!
  • BrianSlickBrianSlick Posts: 9,314Tutorial Authors, Registered Users
    Why did you create SectionRoutes? Why not just have to-many relationships in both directions between Sections and Routes?

    Incidentally, I'd recommend going singular with entity names - Section, Route, Grade - and only going plural with to-many relationships.
  • TonyTony Posts: 12Registered Users
    Fstuff;431332 said:
    This seems like a possible explanation for what you are seeing. If each Route has a pointer to a Grade, but you then point a different Route to the same Grade, the first Route will then point to nil. That sounds wordy, perhaps a pseduocode explanation will illuminate:
    Route *a = ...;
    Route *b = ...;
    Grade *X = ...;

    a.grade = X; // a.grade == X, b.grade == nil
    b.grade = X; // a.grade == nil, b.grade == X
    So, I would first check to make sure that your Core Data schema matches the web service schema (i.e., your web service enforces the 1:1 relationship b/w Route and Grade). Then I would check that you are implementing this correctly when creating your Core Data objects (e.g., that you aren't recycling the same Grade object when parsing the data you receive, etc).

    Good luck!
    Hi Fstuff,

    Much thanks for your response, it helped me resolve the issue. Can't believe how simple it was but you nailed it with the following:

    "If each Route has a pointer to a Grade, but you then point a different Route to the same Grade, the first Route will then point to nil."

    A one-to-one relationship between Routes and Grades is incorrect because one grade could belong to many routes, changing the cardinality to one-to-many (Grades -< Routes) resolved the issue. Thank you!
    BrianSlick;431356 said:
    Why did you create SectionRoutes? Why not just have to-many relationships in both directions between Sections and Routes?

    Incidentally, I'd recommend going singular with entity names - Section, Route, Grade - and only going plural with to-many relationships.

    BrianSlick, Thanks for your response! I introduced SectionRoutes to act as a lookup / junction entity, probably worth me pointing out at this point that I'm still approaching my core data schema design with the mindset of a designing a database for an RDMS like MSSQL / MySQL, and in doing so I introduced a lookup / junction table to minimise redundant data in either the Section or Route entities if one route belongs to many sections and vice versa - in a normal database I usually include a lookup table when I'm dealing with many-to-many relationships with the lookup table being on the many side of a one-to-many relationship between the other two tables. Introducing the lookup entity has simplified my predicate as well, i simply grab all the routes I want to display for a given Section NSManagedObject as follows:

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"section == %@", _selectedSection];

    Am I correct in saying that, due to core data allowing a person to contain an NSSet of objects in a relationship that if I were to omit my lookup table, I could relate all my routes in one NSSet in the Section entity and vice versa? I need to brush up on the use of NSPredicates a bit more but how would my NSPredicate look like if I wanted to grab all the routes for a given Section NSManagedObject if I had this many-to-many relationship in place?

    Thanks again for the help! (singular vs plural makes total sense, I've changed it)
  • BrianSlickBrianSlick Posts: 9,314Tutorial Authors, Registered Users
    Don't think like SQL, because you aren't using SQL. Core Data may indeed be using SQL behind-the-scenes, but that is an implementation detail that you don't need to worry about. The backing store could just as easily be (on the Mac) XML or a couple other options, and that does not change what you do in code. Don't shoehorn SQL stuff onto the front end.

    There is a means of formulating the predicate for a to-many relationship. I always have to look it up, but it is basically "ANY routes == whatever". If SectionRoutes is helping you to get there, fine, but it isn't necessary and is just causing more work for you in the long run.
  • TonyTony Posts: 12Registered Users
    BrianSlick;431375 said:
    Don't think like SQL, because you aren't using SQL. Core Data may indeed be using SQL behind-the-scenes, but that is an implementation detail that you don't need ....
    I actually tried removing my lookup entity to try resolve my initial issue, and I did land up creating an NSPredicate that looked exactly like the one you've suggested "ANY routes == section"... it returned an error, I can't remember the error I got but I'm going to revisit this now to try remove the lookup table. Feels like I'm limiting myself to the benefits of core data. I'll no doubt post the error soon if I can't work it out :). Thanks again for the help.
Sign In or Register to comment.