Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g (10.1.3.1.0)

Part Number B25947-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

26.6 Using Inheritance in Your Business Domain Layer

Inheritance is a powerful feature of object-oriented development that can simplify development and maintenance when used appropriately. As you've seen in Section 25.9, "Creating Extended Components Using Inheritance", ADF Business Components supports using inheritance to create new components that extend existing ones in order to add additional properties or behavior or modify the behavior of the parent component. This section helps you understand when inheritance can be useful in modeling the different kinds of entities in your reusable business domain layer.


Note:

The examples in this section refer to the InheritanceAndPolymorphicQueries project in the AdvancedEntityExamples workspace. See the note at the beginning of this chapter for download instructions. Run the AlterUsersTable.sql script in the Resources folder against the SRDemo connection to setup the additional database objects required for the project.

26.6.1 Understanding When Inheritance Can be Useful

Your application's database schema might contain tables where different logical kinds of business information are stored in rows of the same table. These tables will typically have one column whose value determines the kind of information stored in each row. For example, the SRDemo application's USERS table stores information about end-users, technicians, and managers in the same table. It contains a USER_ROLE column whose value — user, technician, or manager — determines what kind of user the row represents.

While the simple SRDemo application implementation doesn't yet contain this differentiation in this release, it's reasonable to assume that a future release of the application might require:

  • Managing additional database-backed attributes that are specific to managers or specific to technicians

  • Implementing common behavior for all users that is different for managers or technicians

  • Implementing new functionality that is specific to only managers or only technicians

Figure 26-2 shows what the business domain layer would look like if you created distinct User, Manager, and Technician entity objects to allow distinguishing the different kinds of business information in a more formal way inside your application. Since technicians and managers are special kinds of users, their corresponding entity objects would extend the base User entity object. This base User entity object contains all of the attributes and methods that are common to all types of users. The performUserFeature() method in the figure represents one of these common methods.

Then, for the Manager and Technician entity objects you can add specific additional attributes and methods that are unique to that kind of user. For example, in the figure, Manager has an additional NextReview attribute of type Date to track when the manager must next review his employees. There is also a performManagerFeature() method that is specific to managers. Similarly, the Technician entity object has an additional Certified attribute to track whether the technician has completed training certification. The performTechnicianFeature() is a method that is specific to technicians. Finally, also note that since expertise areas only are relevant for technicians, the association between "users" and expertise levels is defined between Technician and ExpertiseArea.

Figure 26-2 Distinguishing Users, Managers, and Technicians Using Inheritance

Image of inheritance among users

By modeling these different kinds of users as distinct entity objects in an inheritance hierarchy in your domain business layer, you can simplify having them share common data and behavior and implement the aspects of the application that make them distinct.

26.6.2 How To Create Entity Objects in an Inheritance Hierarchy

To create entity objects in an inheritance hierarchy, you use the Create Entity Object wizard to create each entity following the steps outlined in the sections below. The example described here assumes that you've altered the SRDemo application's USERS table by executing the following DDL statement to add two new columns to it:

alter table users add (
  certified varchar2(1),
  next_review date
);

26.6.2.1 Start By Identifying the Discriminator Column and Distinct Values

Before creating entity objects in an inheritance hierarchy based on table containing different kinds of information, you should first identify which column in the table is used to distinguish the kind of row it is. In the SRDemo application's USERS table, this is the USER_ROLE column. Since it helps partition or "discriminate" the rows in the table into separate groups, this column is known as the discriminator column.

Next, determine the valid values that the descriminator column takes on in your table. You might know this off the top of your head, or you could execute a simple SQL statement in the JDeveloper SQL Worksheet to determine the answer. To access the worksheet:

  • Choose View | Connection Navigator.

  • Expand the Database folder and select the SRDemo connection.

  • Choose SQL Worksheet from the right-mouse context menu.

Figure 26-3 shows the results of performing a SELECT DISTINCT query in the SQL Worksheet on the USER_ROLE column in the USERS table. It confirms that the rows are partitioned into three groups based on the USER_ROLE discriminator values: user, technician, and manager.

Figure 26-3 Using the SQL Worksheet to Find Distinct Discriminator Column Values

Image of using SQL Worksheet to find column values

26.6.2.2 Identify the Subset of Attributes Relevant to Each Kind of Entity

Once you know how many different kinds of business entities are stored in the table, you will also know how many entity objects to create to model these distinct items. You'll typically create one entity object per kind of item. Next, in order to help determine which entity should act as the base of the hierarchy, you need to determine which subset of attributes is relevant to each kind of item.

Using the example above, assume you determine that all of the attributes except Certified and NextReview are relevant to all users, that Certified is specific to technicians, and that NextReview is specific to managers. This information leads you to determine that the Users entity object should be the base of the hierarchy, with Manager and Technician entity object each extending Users to add their specific attributes.

26.6.2.3 Creating the Base Entity Object in an Inheritance Hierarchy

To create the base entity object in an inheritance hierarchy, use the Create Entity Object wizard and following these steps:

  • In step 1 on the Name panel, provide a name and package for the entity, and select the schema object on which the entity will be based.

    For example, name the entity object User and base it on the USERS table.

  • In step 2 on the Attributes panel, select the attributes in the Entity Attributes list that are not relevant to the base entity object (if any) and click Remove to remove them.

    For example, remove the Certified and NextReview attributes from the list.

  • In step 3 on the Attribute Settings panel, use the Select Attribute dropdown list to choose the attribute that will act as the discriminator for the family of inherited entity objects and check the Discriminator checkbox to identify it as such. Importantly, you must also supply a Default Value for this discriminator attribute to identify rows of this base entity type.

    For example, select the UserRole attribute, mark it as a discriminator attribute, and set its Default Value to the value "user".


    Note:

    Leaving the Default Value blank for a discriminator attribute is legal. A blank default value means that a row whose discriminator column value IS NULL will be treated as this base entity type.

Then click Finish to create the entity object.

26.6.2.4 Creating a Subtype Entity Object in an Inheritance Hierarchy

To create a subtype entity object in an inheritance hierarchy, first do the following:

  • Determine the entity object that will be the parent entity object from which your new entity object will extend.

    For example, the parent entity for a new Manager entity object will be the User entity created above.

  • Ensure that the parent entity has a discriminator attribute already identified.

    The base type must already have the discriminator attribute identified as described in the section above. If it does not, use the Entity Object editor to set the Discriminator property on the appropriate attribute of the parent entity before creating the inherited child.

Then, use the Create Entity Object wizard and follow these steps to create the new subtype entity object in the hierarchy:

  • In step 1 on the Name panel, provide a name and package for the entity, and click the Browse button next to the Extends field to select the parent entity from which the entity being created will extend.

    For example, name the new entity Manager and select the User entity object in the Extends field.

  • In step 2 on the Attributes panel, use the New from Table button to add the attributes corresponding to the underlying table columns that are specific to this new entity subtype.

    For example, select the NEXT_REVIEW column to add a corresponding NextReview attribute to the Manager entity object

  • Still on step 2, use the Override button to override the discriminator attribute so that you can customize the attribute metadata to supply a distinct Default Value for the Manager subtype.

    For example, override the UserRole NextReview attribute.

  • In step 3 on the Attribute Settings panel, use the Select Attribute dropdown list to choose the discriminator attribute. Importantly, you must change the Default Value field to supply a distinct default value for the discriminator attribute that defines the entity subtype being created.

    For example, select the UserRole attribute and change its Default Value to the value "manager".

Then click Finish to create the subtype entity object.


Note:

You can repeat the same steps to define the Technician entity that extends User to add the additional Certified attribute and overrides the Default Value of the UserRole discriminator attribute to have the value "technician".

26.6.3 How to Add Methods to Entity Objects in an Inheritance Hierarchy

To add methods to entity objects in an inheritance hierarchy, enable the custom Java class for the entity in question and visit the code editor to add the method.

26.6.3.1 Adding Methods Common to All Entity Objects in the Hierarchy

To add a method that is common to all entity objects in the hierarchy, enable a custom Java class for the base entity object in the hierarchy and add the method in the code editor. For example, if you add the following method to the UserImpl class for the base User entity object, it will be inherited by all entity objects in the hierarchy:

// In UserImpl.java
public void performUserFeature() {
  System.out.println("## performUserFeature as User");
}

26.6.3.2 Overriding Common Methods in a Subtype Entity

To override a method in a subtype entity that is common to all entity objects in the hierarchy, enable a custom Java class for the subtype entity and choose Source | Override Methods to launch the Override Methods dialog. Select the method you want to override, and click OK. Then, customize the overridden method's implementation in the code editor. For example, imagine overriding the performUserFeature() method in the ManagerImpl class for the Manager subtype entity object and change the implementation to look like this:

// In ManagerImpl.java
public void performUserFeature() {
  System.out.println("## performUserFeature as Manager");
}

When working with instances of entity objects in a subtype hierarchy, sometimes you will process instances of multiple different subtypes. Since Manager and Technician entities are special kinds of User, you can write code that works with all of them using the more generic UserImpl type that they all have in common. When doing this generic kind of processing of classes that might be one of a family of subtypes in a hierarchy, Java will always invoke the most specific override of a method available.

This means that invoking the performUserFeature() method on an instance of UserImpl that happens to really be the more specific ManagerImpl subtype, will the result in printing out the following:

## performUserFeature as Manager

instead of the default result that regular UserImpl instances would get:

## performUserFeature as User

26.6.3.3 Adding Methods Specific to a Subtype Entity

To add a method that is specific to a subtype entity object in the hierarchy, enable a custom Java class for that entity and add the method in the code editor. For example, you could add the following method to the ManagerImpl class for the Manager subtype entity object:

// In ManagerImpl.java
public void performManagerFeature() {
  System.out.println("## performManagerFeature called");    
}

26.6.4 What You May Need to Know

{para}?>

26.6.4.1 Sometimes You Need to Introduce a New Base Entity

In the example above, the User entity object corresponded to a concrete kind of row in the USERS table and it also played the role of the base entity in the hierarchy. In other words, all of its attributes were common to all entity objects in the hierarchy. You might wonder what would happen, however, if the User entity required a property that was specific to users, but not common to managers or technicians. Imagine that end-users can participate in customer satisfaction surveys, but that managers and technicians do not. The User entity would require a LastSurveyDate attribute to handle this requirement, but it wouldn't make sense to have Manager and Technician entity objects inherit it.

In this case, you can introduce a new entity object called BaseUser to act as the base entity in the hierarchy. It would have all of the attributes common to all User, Manager, and Technician entity objects. Then each of the three entities the correspond to concrete rows that appear in the table could have some attributes that are inherited from BaseUser and some that are specific to its subtype. In the BaseUser type, so long as you mark the UserRole attribute as a discriminator attribute, you can just leave the Default Value blank (or some other value that does not occur in the USER_ROLE column in the table). Because at runtime you'll never be using instances of the BaseUser entity, it doesn't really matter what its discriminator default value is.

26.6.4.2 Finding Subtype Entities by Primary Key

When you use the findByPrimaryKey() method on an entity definition, it only searches the entity cache for the entity object type on which you call it. In the example above, this means that if you call UserImpl.getDefinitionObject() to access the entity definition for the User entity object when you call findByPrimaryKey() on it, you will only find entities in the cache that happen to be users. Sometimes this is exactly the behavior you want. However, if you want to find an entity object by primary key allowing the possibility that it might be a subtype in an inheritance hierarchy, then you can use the EntityDefImpl class' findByPKExtended() method instead. In the User example described here, this alternative finder method would find an entity object by primary key whether it is a User, Manager, or Technician. You can then use the Java instanceof operator to test which type you found, and then cast the UserImpl object to the more specific entity object type in order to work with features specific to that subtype.

26.6.4.3 You Can Create View Objects with Polymorphic Entity Usages

When you create an entity-based view object with an entity usage corresponding to a base entity object in an inheritance hierarchy, you can configure the view object to query rows corresponding to multiple different subtypes in the base entity's subtype hierarchy. Each row in the view object will use the appropriate subtype entity object as the entity row part, based on matching the value of the discriminator attribute. See Section 27.6.2, "How To Create a View Object with a Polymorphic Entity Usage" for specific instructions on setting up and using these view objects.