Object Relations

In this chapter you will learn how to implement object relations. The project's state at the start of this chapter is archived in snapshot2.zip. However, the preferred way to get your project in sync with the tutorial is to download and unpack update2.zip, as this will only contain the changed files.

The Invoicer's Relations

Tentackle supports all well known relation types, i.e. 1:1, 1:N, N:1 and N:M. Furthermore, it can handle compositions and allows different kinds of object loading strategies such as lazy, eager or cached. Other goodies like cascaded delete are also provided. Please see the documentation for details.
So, what object relations are used in the tutorial's project? Even without a UML class diagram they are easy to find: Please open Invoice.java and modify the relations section (4th comment block):
/**
 * @> $relations
 * # relations for Invoice
 *
 * InvoiceLine:
 *      relation = tracked composite list,
 *      link = setInvoice indexed,
 *      select = lazy,
 *      delete = cascade;
 *
 * Customer: select = cached;
 *
 * @<
 */
Similarly, edit InvoiceLine.java:
/**
 * @> $relations
 * # relations for InvoiceLine
 *
 * Product: select=cached;
 *
 * @<
 */
In Invoice.java and InvoiceLine.java please locate the DbMethods wurblet and add the option --tracked:

--tracked option

In Customer.java and Product.java locate the AppDbCache wurblet and uncomment the first wurblet anchor:

--tracked option

Somewhere in InvoiceLine.java, no matter where, add a new wurblet anchor to generate the code for selecting all invoice lines for a given invoice:
  /**
   * Selects all InvoiceLines for a given Invoice.
   * 
   * @param invoiceId the object ID of the invoice
   * @return the list of invoice lines
   *
   * @wurblet selectByInvoiceId AppDbSelectList $mapping $remote --tracked invoiceId
   */
Also in InvoiceLine.java add a method to set the invoice header:
  /**
   * Sets the invoice header for an invoice line.
   *
   * @param invoice the Invoice
   * @param ndx the index of this line within the invoice
   */
  public void setInvoice(Invoice invoice, int ndx) {
    setInvoiceId(invoice == null ? 0 : invoice.getId());
    setInvoiceIndex(ndx);
  }
Press Ctrl-Shift-F11 to run the wurbel-target and inspect the code while fixing the imports. Press F11 to build the project. It should compile without errors.

That's it?

That's it!

Nevertheless, here are some explanations:
Looking at Invoice.java you will find some code generated by the AppDbRelations-wurblet. By overriding and implementing several methods this wurblet configures the generic persistence layer in such a way that invoking the save()-method of an Invoice-object will persist all changes or modifications of the invoice and all its invoice lines. Similarly, delete() will remove the invoice with all its lines. Furthermore, the persistence layer will take care of transactions while minimizing the number of roundtrips between the application and the database backend.
You have also learned one of the major principles of the agile generative programming approach with Tentackle: whenever you need a feature (or aspect, functionality, whatever term you prefer), chances are high that you merely need to add a wurblet anchor that will generate working code according to your application specific model. The caching in Customer or the method InvoiceLine.selectByInvoiceId are good examples.

... next step >