Wednesday, December 13, 2006

Displaying all columns in ADF table (TopLink entity)

If you are using ADF Faces table, that is based on TopLink entity bean and is generated from Data Control, by default you can not show columns involved into primary-foreign key relationship. It is because, Data Control generated based on Session Facade does not allow to display columns of ValueHolderInterface type, only data types (String, Integer, etc.) are allowed. For example, if we have Regions(regionId, regionName) and Countries(countryId, countryName, regionId) tables, by default it will not be possible to generate such ADF Faces table - Table(countryId, countryName, regionName).

How to show all columns? I have solved this, by adding one getter method to Countries TopLink entity bean:

public String getRegionName() {
return this.getRegions().getRegionName();
}

You can download sample application I have developed to solve this issue - AllColumns.zip (JDeveloper 10.1.3.1). Application description:
  1. As a datasource, standard HR schema is used
  2. Two entity objects are generated - Regions and Countries
  3. Getter for regionName is added into Countries TopLink entity bean
  4. Session Facade and Data Control are created
  5. To countries.jspx page, Countries Method Return is dragged and dropped from Data Control Pallete.
Generated Data Control, regionName involved into primary-foreign key relationship is available:


Data displayed on countries.jspx page:

19 comments:

Anonymous said...

Hi,

I am trying to get regionName appear in the findAllCountries() as shown in this article.

However I always get:

- findAllCountries
- Countries
countryId
countryName
+ regions
+ getRegionName()
+ operations

I have added
public String getRegionName() {
return this.getRegions().getRegionName();
}
to the countries.java (bean) prior to 'Create Data Control'


Is there something I have missed?
Using Jdeveloper V10.1.3.2.0

with thanks, Joe.

Andrej Baranovskij said...

Hi,

I have checked sample available in AllColumns.zip using JDeveloper 10.1.3.2 - it works ok.

If you have added getRegionName() method into Contries.java entity bean, try to check Countries.xml file. This file is generated for Contries.java after making 'Create Data Control'. There you should find attribute declaration for 'regionName' - Attribute Name="regionName" IsUpdateable="0" Type="java.lang.String"

Have you tried to open my sample?

Regards,
Andrejus

Anonymous said...

Hi Andrejus,

I found I had to:

1. add the setter to the countries.java file
2. create the data control (this overwrites the existing entity.xml file)
3. manually edit countries.xml to add
Attribute Name="regionName" IsUpdateable="0" Type="java.lang.String"
4. do a refresh of the generated data control, in my case hrMap1TLmapDataControl

Thanks again it all works.
Joe.

Anonymous said...

Hm, that's not a solution, that's a workaround. OK, having these classes it works fin. But what if you have more members? or more contained classes? or contained classes in the contained classes (eg the region class may have an object of type "continent"); you should expose continent info to region and then expose again to country.
The JDev/ADF team should do something more clever here :)

Andrej Baranovskij said...

I hope, solution will be available in 11g Release :)

Anonymous said...

helal olsun andrejus kardeşim benim bi tanesin...

I mean...

Thank you Andre...I can't believe ADF does not automatically (via valueholder objects) support such a common issue that we programmers often encounter in our designs.
Thanks again for this simple and very useful solution.

M.Ali - Turkey

Anonymous said...

Hi Andrejus,

First of all my compliments for your great Blog! I knew your name, but now I know your contribution to the Java community as well.

I’m studying the EJB and I did run into the problem that by default columns involved into primary-foreign key relationships cannot be displayed. To be honest, I have no clue how you did create this example application? I use Toplink Essential and EJB Libraries for my project. I guess you did use Toplink? Please clarify which Wizards/technologies can be used to create your code. I don’t think that you typed all that XML…

I can be completely wrong and confused in my ‘misunderstanding’, but I would like to know if my solution to display the Manager’s Last Name on Department records yields a equally result as the example demonstrated here. The relation in my Entity Bean is like:

@ManyToOne
@JoinColumn(name = "MANAGER_ID", referencedColumnName = "EMPLOYEE_ID")
private Employee employee;

I did add a Transient attribute “managerLastName” and method to obtain the Last Name via the relation:

@Transient
private String managerLastName;

public String getManagerLastName() {
String name = "";
if(!(getEmployee() == null)){
name = getEmployee().getLastName();
}
return name;
}

The check on existing Employee objects (getEmployee() == null) was required to prevent annoying NullPointerExceptions when no manager was assigned to a Department. The transient attribute was correctly displayed in my ADF Faces table.

I would appreciate it very much if you can tell me where I can find background information, or even better: a working example, about Query Find Forms in relation to ADF Faces Tables. All documentation supplied by Oracle is based on ADF BC as Business Service.

Regards,

M. Kreuwels

Andrej Baranovskij said...

Hello,

Thanks for good feedback! :)

Yes, I'm using TopLink here - but it's not TopLink Essentials (TopLink Essentials is lighter version). Sample is developed using JDeveloper wizards for TopLink and ADF development.

You can find Oracle documentation that is related completely to TopLink track in this step-by-step tutorial: Oracle Application Development Framework: Tutorial 10g Release 3 (10.1.3) . Also there exists developer guide for TopLink track: Advanced TopLink Topics.

Inform me, about your success.

Regards,
Andrejus

VB said...

Hi Andre,

This is vimalan again for different problem.

Example UserTable and PaymentTable

UserTable - UserID - Primary Key

PaymentTable - containg couple of fields and UserId is foreign Key.

I designed the page for to insert the new input record using the steps given in the doc "http://download-uk.oracle.com/docs/cd/B32110_01/web.1013/b28967/web_adv007.htm".

When i click the persistEntity method its throws TopLink error cannot insert null value into UserId column in PaymentTable.

Please tell how to populate the values from the screen to PaymentTable.

Thanks & Regards
Vimalan Balan

Andrej Baranovskij said...

Hi Vimalan,

You can try to persist First entity and after it will be stored, you can persiste Second entity.

However, there can be many reasons why it dont work in your case, I'm not sure exactly why.

You can check TopLink forum on OTN as well.

Regards,
Andrejus

VB said...

Hi Andre,

Thanks and if you can send or post a sample for to input new record.

Thanks & Regards
Vimalan Balan

Andrej Baranovskij said...

Hi Vimalan,

I dont have sample for this case.

You need to do develop it :-)

Regards,
Andrejus

VB said...

Hi Andre,

I developed the application. EgovAgencyDetails.java and EgvoPaymentorderMaster .java file. I designed the page and create custom method for to insert record in Payment table.

public EgvoPaymentorderMaster createServiceRequest( Passing parameters from the screen)
{
UnitOfWork uow = getSessionFactory().acquireUnitOfWork();
final EgovAgencyDetails product =
(EgovAgencyDetails)uow.executeQuery("findAgencyRegistrationNo", EgovAgencyDetails.class, agencyRegistrationNo);

EgvoPaymentorderMaster newInstance =
(EgvoPaymentorderMaster)uow.newInstance(EgvoPaymentorderMaster.class);
newInstance.setPoid(poId);
.....
.....

product.addEgvoPaymentorderMaster(newInstance);
}

Now i am getting error that can't insert Null column in EgovAgencyDetails table.

I don't know where is the problem.
Please can you tell the fix or anything i need to do the mapping in JDeveloper 10.1.3.3

Thanks & Regards
Vimalan Balan

VB said...

Hi Andre,

I found out the problem and fixed the error. Now its inserting into the payment table.

Problem is in mapping. In primary table, we will have collection list for the Payment table. There we need to map the table reference. i.e Source Field and Target Field.

Thanks & Regards
Vimalan Balan

Unknown said...

vimalan,

Could you please explain your fix for the null issue a little more. I am extremely new to toplink and am not sure how to fix the mapping issue.

Andrej Baranovskij said...

Daniel,

You have this issue with my sample? What exactly problem you have?

Thanks,
Andrejus

Unknown said...

Hi Andrejus,

I tried getting some help from the Oracle forums with no luck. I think I may just have to find another approach.

Here's the thread from the forums; my user name is dmccabe1.
http://forums.oracle.com/forums/thread.jspa?threadID=445234

Thanks, Daniel

Anonymous said...

This is a great example! Exactly what I need. However, I am trying to implement it in EclipseLink JPA and am having trouble finding examples how to do this. When I add a ValueHolderInterface, replacing a desired POJO attribute when I use the class I get the message "... not a valid type for a serialized mapping. The attribute must implement the Serializable inteface". I was hoping not to have to modify the ValueHolderInterface and since I'm new to this I have probably overlooking something... please help!

Anonymous said...

Hi Andrejus

Do you know how to do it on javax.persistence Enities. Let say Im trying to do the same but in my data control i got the object regions within countrines by @ManyToOne definition I just drag regionName to the column, If I test with java client everithing is ok, if I do it on table it fails and just show the last record for all the rows.