7

I'm trying to set up a simple Core Data model like the following:

Order(code, customer)
Book(code, title, price)
OrderBook(order_code, book_code, quantity)

From Core Data documentation I see that it's not possible to model a many-to-many relationship adding to it attributes. For this reason I modeled it like the following.

enter image description here

where:

  • from Order to OrderBook there is a one-to-many relationship with a delete rule Cascade
  • form OrderBook to Order there is a one-to-one relationship with a delete rule No Action

The same is valid for Book and OrderBook.

First question: Is this model valid?

Supposing that the model is ok, I created the corresponding NSManagedObject subclasses.

Book.h/.m
Order.h/.m
OrderBook.h/.m

That said, I have the necessity to populate the corresponding db by means of Core Data mechanism. To do this I created the corresponding categories like the following, where each category is responsible to create itself (to maintain object encapsulation).

Book+Creation.h/.m
Order+Creation.h/.m
OrderBook+Creation.h/.m

For example Book+Creation category has a class method like the following:

+ (Book *)bookWithXMLElement:(GDataXMLElement *)xmlElement inManagedObjectContext:(NSManagedObjectContext *)context;

Now I have a problem and I don't know how to resolve it.

The model population has to happen at different times. The table for books is populated first (I'm creating a catalog of books from an xml file). Once finished, I'm able to populate order and orderbook tables. To populate these tables I'm using an xml file like the following:

<orders>
  <order>
     <code>1234</code>
     <book>2567</book>
     <customer>299</customer>
     <quantity>4</quantity>
  </order>
</orders>

To create an Order managed object I've created the following method in its category Order+Creation:

+ (Order *)orderWithXMLElement:(GDataXMLElement *)xmlElement inManagedObjectContext:(NSManagedObjectContext *)context;

Once created, the object is passed to OrderBook+Creation class method category to create an OrderBook managed object:

+ (OrderBook *)orderWithXMLElement:(GDataXMLElement *)xmlElement withOrder:(Order*)order inManagedObjectContext:(NSManagedObjectContext *)context
{
  OrderBook* orderBook = [NSEntityDescription insertNewObjectForEntityForName:@"OrderBook" inManagedObjectContext:context];
  orderBook.order = order;
  //orderBook.book = <-- how can I retrieve the book?

  return orderBook;
}

What is missing is how to create (or retrieve) the Book object to assign it to OrderBook object.

Second question: How can I retrieve a Book object and assign it to OrderBook? Do I have to create a NSFetchRequest to fetch the right object Book (the one that has the same code in xml file, e.g. <book>2567</book>)? If so, is there a mechanism to improve performance for the fetching rquest?

Remember that book table is already populated.

Hope it is clear. Thank you in advance.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
  • With your current model, if you have an order book object which has both a book and and order attribute, if you delete either the book or the order, the order book object will be removed. Is that what you want? – jrturton Feb 18 '12 at 13:54
  • @jrturton thanks for your reply. Yes,it's what I want. Do you have any suggestions? – Lorenzo B Feb 18 '12 at 13:57
  • @jrturton Deleting an order or a book, the order-book obj (the order-book row, speaking in db terms) also will be deleted. – Lorenzo B Feb 18 '12 at 14:05

1 Answers1

3
  1. Should be "nullify" not "no action" for the to-one relationships.
  2. Yes, you're right, you need a fetch request.

If you have performance problems with the fetch request (hard to say without knowing the numbers involved) you could fetch the whole set of books into memory (again, might not be practical depending on the numbers) and then use array filtering/enumeration to find the specific item, but you should definitely build and profile the simplest option first.

The delete rule types are described here, nullify is correct for the to-one relationship from orderBook to Book and Order:

Nullify

Set the inverse relationship for objects at the destination to null.

For example, if you delete a department, set the department for all the current members to null. This only makes sense if the department relationship for an employee is optional, or if you ensure that you set a new department for each of the employees before the next save operation.

This means if you delete an orderBook, then it is removed from the orderBooks and bookOrders sets in the Order and Book entities.

Community
  • 1
  • 1
jrturton
  • 118,105
  • 32
  • 252
  • 268
  • Thanks. Table population is done in the background by mean of a NSOperation. What do you means by "you should definitely build and profile the simplest option first"? +1 for your support. – Lorenzo B Feb 18 '12 at 14:21
  • 1
    I mean, write it with a fetch request (you only need to create it once, you can just modify the predicate) and use the returned book object when populating your order. Don't try anything else until and unless this causes problems. – jrturton Feb 18 '12 at 14:32
  • A simple question for you. Is is it correct that **from OrderBook to Order there is a one-to-one relationship with a delete rule No Action**?. When I set this the compiler gives me a Consistency Error. Maybe if I use NULLIFY rule could be more correct. What do you think about? Thanks. – Lorenzo B Feb 20 '12 at 09:39
  • Yes, both your "no actions" should be nullify, I misread your question earlier (was focussing on the cascade part) – jrturton Feb 20 '12 at 10:15
  • Thanks. But with no action instead of nullify what could be the problem? With **no action**, if I remove a row from OrderBook entity (table) NSSets (both for Book and Order) are not updated correctly, is it true? Could you provide me an example. – Lorenzo B Feb 20 '12 at 11:02
  • I'm not sure what you are after. The various rules are described here: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html and you would want the sets in Order and Book to have the deleted item removed from them, so Nullify is the right choice. – jrturton Feb 20 '12 at 11:47