Why Do I Get the InvalidOwnerException?

Send me a mail
 Dive into Oracle ADF   Click to see the XML version of this web page.   (Updated: 2/3/2008; 9:24:22 PM.)
Tips and tricks from Steve Muench on Oracle ADF Framework and JDeveloper IDE

Why Do I Get the InvalidOwnerException?

One of the most frequently reported questions that users have when learning BC4J is, "Why am I getting the oracle.jbo.InvalidOwnerException: JBO-25030: Failed to find or invalidate owning entity error when I try to insert a new detail row into a master/detail pair of rowsets?

Let's consider some typical business objects like Order and LineItem. This error is thrown when the developer has consciously modeled the relationship between Order and LineItem entity objects using a strong composition relationship, instead of a simple association relationship. Marking an association between Order and LineItem entity objects as a strong composition is telling the BC4J framework that LineItem instances are "owned by" or "contained by" a particular Order object instance. A corollary is that a strong composition is saying, "Don't let there ever exist orphaned LineItems that aren't part of a well-known Order!"

And so, if you fail to provide the context for the owning Order when you create a LineItem -- when composition is in play -- then you get this error. Using view objects (the BC4J framework component that encapsulates a SQL query and let's you work with its rowset of results), there are two ways to avoid this error:

  1. Make sure you've related your OrderView and LineItemView by a view link, and create the new LineItem row by first finding the OrderView row you want to work with (using findByKey or setting appropriate bind variables and executing the query), then by getting the RowIterator for the detail collection of LineItemView rows by accessing the view link accessor attribute, then use this iterator to call createRow() to create the detail LineItemView row. 
  2. Alternatively, you can directly create a new row in the LineItemView view object using the createAndInitRow() by passing an appropriately constructed instance of oracle.jbo.NameValuePairs which includes the "OrderId" (foreign key attribute that provides the context for which order this new line item is owned by), and the property value for it.

Here's a code sample:

package test;
import oracle.jbo.client.Configuration;
import oracle.jbo.*;
import oracle.jbo.domain.Number;
public class Test  {
  public static void main(String[] args) {
    String _am = "test.TestModule", _cf = "TestModuleLocal";
    ApplicationModule am = Configuration.createRootApplicationModule(_am,_cf);
    ViewObject lines = am.findViewObject("TopLevelLineItemView");
     * You can use createAndInitRow() to supply the needed
     * foreign key value to order at line row create time.
    Row newLine = lines.createAndInitRow(new NameValuePairs(new String[]{"Orderid"},
                                                        new Object[]{new Number(12345)}));
    newLine.setAttribute("Itemid", "CRU-1234");
    newLine.setAttribute("Quantity", new Number(1));
* Or else, you can get a row of the parent view
    ViewObject orders =   am.findViewObject("OrderView");
* Just use the first order in the view as an example
    Row existingOrder = orders.first();
* Then get the details iterator via the View Link attribute accessor
    RowIterator linesIter = (RowIterator)existingOrder.getAttribute("LinesItemsForOrder");
* Then use this iterator to create the new Line
    newLine = linesIter.createRow();
    newLine.setAttribute("Itemid", "XYZ-1234");
    newLine.setAttribute("Quantity", new Number(4));
* Everything worked, so rollback so we don't actually create the new rows

© Copyright 2008 Steve Muench. Click here to send an email to the editor of this weblog.
Last update: 2/3/2008; 9:24:22 PM.