Showing posts with label Master-Detail. Show all posts
Showing posts with label Master-Detail. Show all posts

Friday, September 19, 2014

ADF - View Link Accessor Type and Cardinality

A view link associates two view objects to form a master-detail relationship. A view link accessor specifies an accessor attribute by which a view row at one end of a master-detail relationship specified by a view link can access the related view row or rows at the other end of the relationship. When you select to generate the custom view row class for the view object with an accessor, JDeveloper will uses the accessor's name to generate the corresponding view link accessor method, a getter method in the view row class.

By default, JDeveloper generates the view link accessor type and the corresponding view link accessor method return type with respect to the cardinality of the view link. For a "many" side of a view link, the view link accessor type will be "oracle.jbo.RowIterator"; for a "one" side, the view link accessor will have the type of "oracle.jbo.Row". This default behavior is acceptable in a majority of cases. For example:

View Object: DepartmentView

  <ViewLinkAccessor
    Name="EmployeesView"
    ViewLink="model.views.links.EmpToDeptLink"
    Type="oracle.jbo.RowIterator"
    IsUpdateable="false"/>

View Object: EmployeeView

  <ViewLinkAccessor
    Name="DepartmentView"
    ViewLink="model.views.links.EmpToDeptLink"
    Type="oracle.jbo.Row"
    IsUpdateable="false"/>

Sometimes, you may want to change this default behavior. In my case, I have a one-to-one master-detail composition relationship between UserView and ContactInfoView. For a new user, once a new user view row is created, a linked contact information view row is required to be created. In the UserView, the view link accessor for the ContactInfoView is defined by default as the following:

  <ViewLinkAccessor
    Name="ContactInfoView"
    ViewLink="model.views.links.UserToContactInfoLink"
    Type="oracle.jbo.Row"
    IsUpdateable="false"/>

I want the view link accessor type to be "oracle.jbo.RowIterator", so that from the user view row, I can use the accessor to create the associated contact information view row.

Fortunately, we can manually change the accessor type from "oracle.jbo.Row" to "oracle.jbo.RowIterator" in the source code of the view object:

View Object: UserView

  <ViewLinkAccessor
    Name="ContactInfoView"
    ViewLink="model.views.links.UserToContactInfoLink"
    Type="oracle.jbo.RowIterator"
    IsUpdateable="false"/>

In case you have already generated the custom view row class, you can manually fix the return type of the view link accessor method.

Now, with this view accessor, I can create contact information view row from a user view row with the code like this:

  userViewRow.getContactInfoView().createRow();


Monday, May 5, 2014

ADF - DBSequence Attribute Does Not Refresh on Insert Because of Wrong SQLType

In this post, I would like to describe a special case related to the ADF entity attribute of type DBSequence.

To quote the documentation for DBSequence type from Developing Fusion Web Applications with Oracle Application Development Framework (12.1.2):

When you create a new entity row whose primary key is a DBSequence, a unique negative number is assigned as its temporary value. This value acts as the primary key for the duration of the transaction in which it is created. If you are creating a set of interrelated entities in the same transaction, you can assign this temporary value as a foreign key value on other new, related entity rows. At transaction commit time, the entity object issues its INSERT operation using the RETURNING INTO clause to retrieve the actual database trigger-assigned primary key value. In a composition relationship, any related new entities that previously used the temporary negative value as a foreign key will get that value updated to reflect the actual new primary key of the master.

In my case, for some reason, the DBSequence primary key is defined with the wrong SQLType "FLOAT" instead of "NUMERIC" as shown in the following code snippet:

<Attribute
    Name="Id"
    ColumnName="ID"
    SQLType="FLOAT"
    Type="oracle.jbo.domain.DBSequence"
    DefaultValue="@0"
    ColumnType="NUMBER"
    PrimaryKey="true"
    RetrievedOnInsert="true"
    IsUpdateable="false"

With this definition, the new entity instance can be posted to the database. The primary key can be correctly assigned by the trigger. But the entity instance cannot be updated with the assigned primary key value from the database.

In a composition relationship, the related new entities that use the DBSequence primary key as a foreign key will fail to be posted to the database due to the attempt to insert NULL into the foreign key column. The error message looks like "ORA-01400: cannot insert NULL into (...)".

To fix this issue, correct the SQLType as the following:

<Attribute
    Name="Id"
    ColumnName="ID"
    SQLType="NUMERIC"
    Type="oracle.jbo.domain.DBSequence"
    DefaultValue="@0"
    ColumnType="NUMBER"
    PrimaryKey="true"
    RetrievedOnInsert="true"
    IsUpdateable="false"

You can find the documentation from:

http://docs.oracle.com/middleware/1212/adf/ADFFD/bcentities.htm#ADFFD19777

And here's API for DBSequence:

http://docs.oracle.com/middleware/1212/adf/ADFMR/oracle/jbo/domain/DBSequence.html