Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)
B25947-01
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

6.6 Configuring Declarative Runtime Behavior

The entity object offers numerous declarative features to simplify implementing typical enterprise business applications. Depending on your task, sometimes the declarative facilities alone may satisfy your needs. However, when you need to go beyond the declarative behavior to implement more complex business logic or validation rules for your business domain layer, that is possible as well. This chapter focuses on giving you a solid understanding of the declarative features. In Chapter 9, "Implementing Programmatic Business Rules in Entity Objects", you'll study some of the most typical ways that you extend entity objects with custom code.

6.6.1 How To Configure Declarative Runtime Behavior

To configure the declarative runtime behavior of an entity object, use the Entity Object Editor. You access the editor by selecting an entity in the Application Navigator and choosing Edit from the context menu. Figure 6-13 shows what the editor looks like for the ServiceRequest entity object.

On the Name page, you can see the entity object's name and configure the database table to which it relates. On the Attributes page, you create or delete the attributes that represent the data relevant to an entity object. By expanding this node, you can access the properties of each of the entity object's attributes.

On the Tuning page, you set options to make database operations more efficient when you create, modify, or delete multiple entities of the same type in a single transaction. On the Publish page, you define events that your entity object can use to notify others of interesting changes in its state, optionally including some or all of the entity object's attributes in the delivered event. On the Subscribe page, you enroll your entity object to be notified when selected events of other entity objects fire. On the Authorization page, you define role-based updatability permissions for any or all attributes. And finally, on the Custom Properties page, you can define custom metadata you can access at runtime on the entity.

Figure 6-13 Use the Entity Object Editor to Configure Its Declarative Features

Image of Entity Object Editor setting declarative features

Note:

If your entity has a long list of attribute names, there's a quick way to find the one you're looking for. With the Attributes node in the tree expanded, you can begin to type the letters of the attribute name and JDeveloper performs an incremental search to take you to its name in the tree.

6.6.2 What Happens When You Configure Declarative Runtime Behavior

All of the declarative settings that describe and control an entity object's runtime behavior are stored in its XML component definition file. When you modify settings of your entity using the editor, pressing OK updates the component's XML definition file and optional custom java files. If you need to immediately apply changes and continue working in the editor, use the Apply button. Applying changes while editing is typically useful only when you enable the generation of a custom Java file for the component for the first time and you want JDeveloper to generate those files before you open another page in the editor.

6.6.3 About the Declarative Entity Object Features

Since much of the entity object's declarative functionality is related to the settings of its attributes, this section covers the important options shown in Figure 6-13 in detail.

6.6.3.1 Legal Database and Java Data types for an Entity Object Attribute

The Persistent property controls whether the attribute value corresponds to a column in the underlying table, or whether it is just a transient value. If the attribute is persistent, the Database Column area lets you change the name of the underlying column that corresponds to the attribute and indicate its column type with precision and scale information (e.g. VARCHAR2(40) or NUMBER(4,2)). Based on this information, at runtime the entity object enforces the maximum length and precision/scale of the attribute value, throwing an exception if a value does not meet the requirements.

Both the Business Components from Tables wizard and the Create Entity Object wizard automatically infer the Java type of each entity object attribute from the SQL type of the database column type of the column to which it is related. The Attribute Type field allows you to change the Java type of the entity attribute to any type you might need. The Database Column Type field reflects the SQL type of the underlying database column to which the attribute is mapped. The value of the Database Column Name field controls the column to which the attribute is mapped.

Your entity object can handle tables with column types, as listed in Table 6-1. With the exception of the java.lang.String class, the default Java attribute types are all in the oracle.jbo.domain and oracle.ord.im packages and support efficiently working with Oracle database data of the corresponding type. The dropdown list for the Java Type field includes a number of other common types that are also supported.

Table 6-1 Default Entity Object Attribute Type Mappings

Oracle Column Type Entity Column Type Entity Java Type

NVARCHAR2(n), VARCHAR2(n), NCHAR VARYING(n), VARCHAR(n)

VARCHAR2

String

NUMBER

NUMBER

Number

DATE

DATE

Date

TIMESTAMP(n), TIMESTAMP(n) WITH TIME ZONE, TIMESTAMP(n) WITH LOCAL TIME ZONE

TIMESTAMP

Date

LONG

LONG

String

RAW(n)

RAW

Raw

LONG RAW

LONG RAW

Raw

ROWID

ROWID

RowID

NCHAR, CHAR

CHAR

String

NCLOB, CLOB

CLOB

ClobDomain

BLOB

BLOB

BlobDomain

BFILE

BFILE

BFileDomain

ORDSYS.ORDIMAGE

ORDSYS.ORDIMAGE

OrdImageDomain

ORDSYS.ORDVIDEO

ORDSYS.ORDVIDEO

OrdVideoDomain

ORDSYS.ORDAUDIO

ORDSYS.ORDAUDIO

OrdAudioDomain

ORDSYS.ORDDOC

ORDSYS.ORDDOC

OrdDocDomain



Note:

In addition to the types mentioned here, you can use any Java object type as an entity object attribute's type, provided it implements the java.io.Serializable interface.

6.6.3.2 Indicating Datatype Length, Precision, and Scale

When working with types that support defining a maximum length like VARCHAR2(n), the Database Column Type field includes the maximum attribute length as part of the value. So, for example, an attribute based on a VARCHAR2(10) column in the database will initially reflect the maximum length of 10 characters by showing VARCHAR2(10) as the Database Column Type. If for some reason you want to restrict the maximum length of the String-valued attribute to fewer characters than the underlying column will allow, just change the maximum length of the Database Column Type value. For example, the EMAIL column in the USERS table is VARCHAR2(50), so by default the Email attribute in the Users entity object defaults to the same. If you know that the actual email addresses are always 8 characters or less, you can update the database column type for the Email attribute to be VARCHAR2(8) to enforce a maximum length of 8 characters at the entity object level.

The same holds for attributes related to database column types that support defining a precision and scale like NUMBER(p[,s]). So, for example, to restrict an attribute based on a NUMBER(7,2) column in the database to have a precision of 5 and a scale of 1 instead, just update the Database Column Type to be NUMBER(5,1).

6.6.3.3 Controlling the Updatability of an Attribute

The Updatable setting controls when the value of a given attribute can be updated. If set to:

  • Always, the attribute is always updatable

  • Never, the attribute is read-only

  • While New, the attribute can be set during the transaction that creates the entity row for the first time, but after being successfully committed to the database the attribute is read-only

6.6.3.4 Making an Attribute Mandatory

The Mandatory property controls whether the field is required.

6.6.3.5 Defining the Primary Key for the Entity

The Primary Key property indicates whether the attribute is part of the key that uniquely identifies the entity. Typically, you will use a single attribute for the primary key, but multiattribute primary keys are fully supported.

At runtime, when you access the related Key object for any entity row using the getKey() method, this Key object contains the value(s) of the primary key attribute(s) for the entity object. If your entity object has multiple primary key attributes, the Key object contains each of their values. It is important to understand that these values appear in the same relative sequential order as the corresponding primary key attributes in the entity object definition.

For example, the ServiceHistory entity object has multiple primary key attributes SvrId and LineNo. On the Attributes page of the Entity Object Editor, SvrId is first, and LineNo is second; an array of values encapsulated by the Key object for a entity row of type ServiceHistory will have these two attribute values in exactly this order. The reason why it is crucial to understand this point is that if you try to use findByPrimaryKey() to find an entity with a multiattribute primary key, and the Key object you construct has these multiple primary key attributes in the wrong order, the entity row will not be found as expected.

6.6.3.6 Defining a Static Default Value

The Default field specifies a static default value for the attribute. For example, you might set the default value of the ServiceRequest entity object's Status attribute to Open, or set the default value of the User entity object's UserRole attribute to user.

6.6.3.7 Synchronization with Trigger-Assigned Values

If you know that the underlying column value will be updated by a database trigger during insert or update operations, you can check the respective Refresh After Insert or Refresh After Update checkboxes to have the framework automatically retrieve the modified value to keep the entity object and database row in sync. The entity object uses the Oracle SQL RETURNING INTO feature, while performing the INSERT or UPDATE to return the modified column back to your application in a single database round-trip.


Note:

If you create an entity object for a synonym that resolves to a remote table over a DBLINK, use of this feature will give an error at runtime like:
JBO-26041: Failed to post data to database during "Update"
## Detail 0 ##
ORA-22816: unsupported feature with RETURNING clause

Section 26.5, "Basing an Entity Object on a Join View or Remote DBLink" describes a technique to circumvent this database limitation.


6.6.3.8 Trigger-Assigned Primary Key Values from a Database Sequence

One common case where Refresh After Insert comes into play is a primary key attribute whose value is assigned by a BEFORE INSERT FOR EACH ROW trigger. Often the trigger assigns the primary key from a database sequence using PL/SQL logic similar to this:

CREATE OR REPLACE TRIGGER ASSIGN_SVR_ID
BEFORE INSERT ON SERVICE_REQUESTS FOR EACH ROW
BEGIN
 IF :NEW.SVR_ID IS NULL OR :NEW.SVR_ID < 0 THEN
   SELECT SERVICE_REQUESTS_SEQ.NEXTVAL
     INTO :NEW.SVR_ID
     FROM DUAL;
   END IF;
END;

Set the Attribute Type to the built-in datatype named DBSequence, as shown in Figure 6-14, and the primary key will be assigned automatically by the database sequence. Setting this datatype automatically enables the Refresh After Insert property.

When you create a new entity row whose primary key is a DBSequence, a unique negative number gets 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. 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.


Note:

As shown in Figure 6-14, you will typically also set the Updatable property of a DBSequence-valued primary key to Never. The entity object assigns the temporary ID, and then refreshes it with the actual ID value after the INSERT option. The end user never needs to update this value.

Figure 6-14 Setting Primary Key Attribute to DBSequence Type Automates Trigger-Assigned Key Handling

Image shows setting DBsequence type

Note:

The sequence name shown on the Sequence tab only comes into play at design time when you use the Create Database Tables... feature described in Section 6.2.6, "Creating Database Tables from Entity Objects". The sequence indicated here will be created along with the table on which the entity object is based.

6.6.3.9 Lost Update Protection

At runtime the framework provides automatic "lost update" detection for entity objects to ensure that a user cannot unknowingly modify data that another user has updated and committed in the meantime. Typically this check is performed by comparing the original values of each persistent entity attribute against the corresponding current column values in the database at the time the underlying row is locked. If an entity object detects that it would be updating a row that is now inconsistent with the current state of the database, it raises the RowInconsistentException.

You can make the lost update detection more efficient by identifying an attribute of your entity whose value you know will get updated whenever the entity gets modified. Typical candidates include a version number column or an updated date column in the row. The change indicator attribute value might be assigned by a database trigger you've written and refreshed in the entity object using the Refresh After Insert and Refresh After Update properties. Alternatively, you can indicate that the entity object should manage updating the change indicate attribute's value using the history attribute feature described in the next section. To detect whether the row has been modified since the user queried it in the most efficient way, select the Change Indicator to compare only the change indicator attribute values.

6.6.3.10 History Attributes

Frequently, you'll need to keep track of historical information in your entity object like:

  • Who created this entity?

  • When did they create it?

  • Who last modified this entity?

  • When did they modify it?

  • How many times has this row been modified?

Entity objects store this information in a History Column attribute, as shown in Figure 6-15.

If an attribute's datatype is Number, String, or Date, and it is not part of the primary key, then you can enable this property to have your entity automatically maintain the attribute's value for historical auditing. How the attribute gets handled depends on the history attribute type that you indicate. If you choose the Version Number type of history column, ADF will automatically increment the value of the numeric attribute every time the object is updated. If you choose Created By, Created On, Modified By, or Modified On, the value will be updated with the current user's username or the current date, respectively, when the object is created or modified.

Figure 6-15 Defaulting a Date tor the Current Database Time Using a History Attribute

Image shows selecting value from History column

6.6.3.11 Setting the Discriminator Attribute for Entity Object Inheritance Hierarchies

Sometimes a single database table stores information about several different kinds of logically related objects. For example, a payroll application might work with hourly, salaried, and contract employees all stored in a single EMPLOYEES table with an EMPLOYEE_TYPE column. The value of the EMPLOYEE_TYPE column indicates with a value like H, S, or C, whether a given row represents an hourly, salaried, or contract employee respectively. While many employee attributes and behavior are the same for all employees, certain properties and business logic depends on the type of employee. In this situation it can be convenient to represent these different types of employees using an inheritance hierarchy. Attributes and methods common to all employees can be part of a base Employee entity object, while subtype entity objects like HourlyEmployee, SalariedEmployee, and ContractEmployee extend the base Employee object and add additional properties and behavior. The Discriminator attribute property is used to indicate which attribute's value distinguishes the type of row. Section 26.6, "Using Inheritance in Your Business Domain Layer" explains how to set up and use inheritance.

6.6.3.12 Understanding and Configuring Composition Behavior

When an entity object composes other entities, it exhibits additional runtime behavior to correctly play its role as a logical container of other nested entity object parts. The following features are always enabled for composing entity objects:

6.6.3.12.1 Orphan-row Protection for New Composed Entities

When a composed entity object is created, it performs an existence check on the value of its foreign key attribute to ensure that it identifies an existing entity as its owning parent entity. Failure to provide a value for the foreign key at create time, or providing a value that does not identify an existing entity object, throws an InvalidOwnerException instead of allowing an "orphaned" child row to be created with no well-identified parent entity.


Note:

The existence check performed finds new pending entities in the current transaction, as well as existing ones in the database if necessary.

6.6.3.12.2 Ordering of Changes Saved to the Database

This feature ensures that the sequence of DML operations performed in a transaction involving both composing and composed entity objects is performed in the correct order. For example, an INSERT statement for a new composing parent entity object will be performed before the DML operations related to any composed children.

6.6.3.12.3 Cascade Update of Composed Details from Refresh-On-Insert Primary Keys

When a new entity row having a Refresh On Insert primary key is saved, after its trigger-assigned primary value is retrieved, any composed entities will automatically have their foreign key attribute values updated to reflect the new primary key value.

There are a number of additional composition related features that you can control through settings on the Association Properties page of the Create Association wizard or the Association Editor. Figure 6-16 shows this page for the ServiceHistoriesForServiceRequest association between the ServiceRequest and ServiceHistory entity objects. These settings are the defaults that result from reverse-engineering the composition from an ON DELETE CASCADE foreign key constraint in the database.

Figure 6-16 Composition Settings for ServiceHistoriesForServiceRequest Association

Image shows Association Properties page

The additional features, and the properties that affect their behavior, include the following:

6.6.3.12.4 Cascade Delete Support

You can either enable or prevent the deletion of a composing parent while composed children entities exist. When the Implement Cascade Delete is unchecked, the removal of the composing entity object is prevented if it contains any composed children. When checked, this option allows the composing entity object to be removed unconditionally and composed children entities are also removed. If the related Optimize for Database Cascade Delete option is unchecked, then the composed entity objects perform their normal DELETE statement at transaction commit time to make the changes permanent. If the option is checked, then the composed entities do not perform the DELETE statement on the assumption that the database ON DELETE CASCADE constraint will handle the deletion of the corresponding rows.

6.6.3.12.5 Cascade Update of Foreign Key Attributes When Primary Key Changes

By checking the Cascade Update Key Attributes option, you can enable the automatic update of the foreign key attribute values in composed entities when the primary key value of the composing entity is changed.

6.6.3.12.6 Locking of Composite Parent Entities

Using the Lock Top-Level Container option, you can control whether adding, removing, or modifying a composed detail entity row should attempt to lock the composing entity before allowing the changes to be saved.

6.6.3.12.7 Updating of Composing Parent History Attributes

Using the Update Top-Level History Columns option, you can control whether adding, removing, or modifying a composed detail entity object should update the Modified By and Modified On history attributes of the composing parent entity.