2010年11月22日星期一

Master-Detail Inserting in ADF BC

This tutorial illustrates how to manage composite association in a one-to-many mapping (with foreign key) and many-to-many mapping (with intersection table) in ADF BC, including how to configure the EO/Association and how to write custom code.

Assumption:  all the table’s primary keys are handled by native database sequence and trigger.

There are three tables in the database, PERSONS, PROJECTS, and PROJECT_PARTICIPATE, which is the intersection table. The database schema as below:

database-schema

Section A: One-to-Many scenario, take PERSONS and PROJECT_PARTICIPATION as an example

1. Generate EO, VO, Association, View Link for the table PERSONS and PROJECT_PARTICIPATION

2. Configure the ID attribute in the EOs, the Type as DBSequence, Updatable as ‘Never’, Refresh After as ‘Insert’, the default value as 0 (it’s really wired that the default value has to be configured, otherwise when you adding a new Person, the id attribute will not popup a minus value.

3. In the association’s behavior section, select ‘Composition Association’, also select ‘Optimize for database Cascade Delete’,’Implement Cascade Delete’,  ‘Cascade Update Key Attribute’

The ‘Cascade Update Key Attribute’ is very important, since otherwise the children’s foreign key value would not be updated.

4. Save the configure and run the application module in the BC browser to test the configure.

Section B: Many-to-Many scenario

take PERSONS, PROJECT_PARTICIPATION, PROJECTS as an example

1.  do the same thing to PROJECTS and the association. but when you configure the Composition Association for the other association, there is a warning, just keep it.

2. Save the configure and run the application module in the BC browser to test the configure, it doesn’t work in the second association.

Actually, we are make a mistake in the Composition Association. In a Composition Association, the composition owner and the composing EO have a highly tight relationship.  The composing EO should have only one owner, otherwise, an invalidOwner exception were threw. In our scenario, the ProjectParticipation EO should not have an owner.

We have to handle the second association’s adding and save manually. 

First Let’s do the Master-Detail adding in a non-composition association, that means, we have to handle the parent-children relationship manually.

There are two things we should make sure:

1. The parent object should be posted before the children objects. Since the ADF framework will post the pending changes in an chronological order, we have to overwrite the child entity’s postChange method.

2. After the post of the parent entity, we have to assign the parent entity’s id to the children’s foreign key. That means both the postChange and the refreshFKInNewContainees methods should be overwritten.

Here is the steps:

1. uncheck all the Composition Association in the two association’s behavior sections.

2. Configure the IDs of the EOs as before.

3. Generate the java source file for the three EOs. EOs are : ProjectImpl.java, PersonImpl.java, ProjectParticipateImpl.java

4.  override the postChange(TransactionEvent e) in the ProjectParticipateImpl.java

@Override
public void postChanges(TransactionEvent e) {
    if (this.getPostState() == STATUS_NEW ||
        this.getPostState() == STATUS_MODIFIED) {
        PersonImpl person = (PersonImpl)this.getPerson();
        if (person != null) {
            person.postChanges(e);
        }
        ProjectImpl project = (ProjectImpl)this.getProject();
        if (project != null) {
            project.postChanges(e);
        }
    }
    super.postChanges(e);
}

5. override the postChange() and refreshFKInNewContainees() in the ProjectImpl.java

private RowIterator newProjectParticipations; //as a cache for the two methods

@Override
public void postChanges(TransactionEvent transactionEvent) {
    if (this.getPostState() == STATUS_NEW) {
        this.newProjectParticipations = this.getProjectParticipate();
    }
    super.postChanges(transactionEvent);
}

@Override
protected void refreshFKInNewContainees() {
    if (this.newProjectParticipations != null) {
        Number projectId = this.getId().getSequenceNumber();
        while (this.newProjectParticipations.hasNext()) {
            ProjectParticipateImpl participate =
                (ProjectParticipateImpl)newProjectParticipations.next();
            participate.setProjectId(projectId);
        }
    }
    this.newProjectParticipations = null;
    //super.refreshFKInNewContainees();
}

6. override the postChange() and refreshFKInNewContainees() in the PersonImpl.java

private RowIterator newProjectParticipations;

@Override
public void postChanges(TransactionEvent e) {
    if (this.getPostState() == STATUS_NEW) {
        this.newProjectParticipations = this.getProjectParticipate();
    }
    super.postChanges(e);
}

@Override
protected void refreshFKInNewContainees() {
    if (this.newProjectParticipations != null) {
        Number personId = this.getId().getSequenceNumber();
        while (this.newProjectParticipations.hasNext()) {
            ProjectParticipateImpl participation =
                (ProjectParticipateImpl)this.newProjectParticipations.next();
            participation.setPersonId(personId);
        }
    }
    this.newProjectParticipations = null;
    //super.refreshFKInNewContainees();
}

 

 

7. Save all and test the Adding and saving operation in the BC Browser.

8. The source code and the sql script can be downloaded here. With the generated8 package as the many-to-many composition association and package generated7 as the one-to-many association.  Composition Association Demo