Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 224015

Summary: BIRT table column bindings remain after data set change
Product: z_Archived Reporter: Paul Rogers <progers>
Component: BIRTAssignee: Chen Chao <cchen>
Status: RESOLVED FIXED QA Contact: Maggie Shen <lshen>
Severity: normal    
Priority: P3 CC: bluesoldier, lchan, lzhu, wenfeng.fwd, whe, wyan, xxue, zimmermann.tho, zqian
Version: 2.2.2   
Target Milestone: 4.2.1   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Bug Depends on: 226904    
Bug Blocks:    

Description Paul Rogers CLA 2008-03-25 21:20:48 EDT
Create a BIRT report. Create a data set against the sample database of the form SELECT * FROM CUSTOMERS. Add a table to your design. Add a field to the detail row for CUSTOMERNAME.

Now, decide that you want to limit the number of columns. Change your query from SELECT * to "SELECT CUSTOMERNAME cName, PHONE".

Select the table. Open the property editor, Binding tab. Look at the binding list. Notice that all the old columns remain.

Notice that there is a Refresh button. Perhaps this will clean up the mess. Click it. Notice that the new columns are added to the existing columns, but the invalid columns are still there.

It appears the only workaround is to manually delete the unwanted columns. And, multiple selection is not allowed in the binding list, so it is a slow process of select, click Remove, select, click Remove...

Expected that this kind of busy work would not be required. Here are four suggestions, from most to least convenient for the user.

Best would be to create the default bindings implicitly. It is generally a "good thing" to avoid copies that can get out of sync. Instead of making an explicit copy of the columns into the table binding, let the software do the work at runtime. Specifically, a reference to row["FOO"] would automatically reference dataSetRow["FOO"] if there is no binding in the table of that same name. Then, all my columns automagically pass right through with no copying, no resyncing. (This kind of thing is very easy to implement with JavaScript.)

Second best would be to automatically resync the bindings each time the data set changes.

Third best would be to have the Resync button remove the invalid columns.

Lastly, at least have the Resync button somehow flag the invalid columns so it is easy to figure out which ones to remove without having to do a manual item-by-item comparison.

Note that the same problem will occur with data types. Suppose I change my data set type from String to Integer. I'd have to remember to go and change the table bindings as well. Again, this is the kind of thing that is easy for a user to get wrong, and easy for the software to automate.
Comment 1 Zhiqiang Qian CLA 2008-03-25 23:49:35 EDT
I agree we could have enhancement on column binding validation once dataset changed, which would need Dte provide some helper methods. 

But for the syntax "row["name"]", "name" actually refers to a column binding name. A binding can also refer to other bindings instead of dataset columns. I think this design helps reducing the run-time complexity of guessing if the name is from dataset or column binding.

For the data type, actually current data engine support implicit conversion of types at runtime, for instance: String<->Integer, String<->Date. so normally this will not affect the data result until there's conflict between the new data type and original binding semantic.
Comment 2 Paul Rogers CLA 2008-03-27 18:13:24 EDT
A few clarification comments, FWIW.

The bindings seem like something that should be derived at run time, not cached at design time. A good general principle is to not store anything in the design file unless the user explicitly created it. All else should be derived from the user's design at run time.

Thus, if the table wants bindings for all data row columns, it should generate them at run time based on the state of the design at that moment in time. If the engine needs to create bindings on the table for each data item, it should do so at run time.

Doing the binding at run time eliminates the whole issue of keeping table bindings in sync with the data set and the data items. As it is, that job appears to fall on me: I must take extra steps to doctor up the bindings whenever I change anything. And, I'm actually prevented from changing some things (such as binding names) due to the internal needs of the current binding system.

The binding system seems to be an assistance to the engine, not me. Thus, it should be created implicitly by the engine; I should not have to maintain it explicitly.

This is akin to a compiler. Source code in Java references other objects. The Java runtime may well convert these into actual pointer references. But, such references are not cached in the Java source; they are computed at compile and/or run time.

As for the naming issue; the vast majority of the time users will choose unique names for columns. After all, if I have an aggregate Foo and a column Foo, how am I going to keep them straight? Unique name requirements are well understood, and it is much easier for an old brain like mine to remember "use unique names" than it is to remember when I use row, when to use dataSetRow, when to create bindings, etc.

Ultimately, the question comes down to ease of use: what is easier for the user who does not have a deep understanding of the binding system.

Again, just my thoughts, FWIW.
Comment 3 Wenfeng Li CLA 2008-04-14 14:22:32 EDT
make bugzila  226904 link to this one.
Comment 4 Chen Chao CLA 2012-08-21 02:58:46 EDT
Fixed it.

Add a clear button on the binding page.
Comment 5 Thomas Zimmermann CLA 2012-09-30 07:58:24 EDT
Hi, I think this is a step in the right direction, but if I am not mistaken, the same behaviour was always available through simple re-binding of the dataset to the report item.
The first suggestion from Paul Rogers sounds like the best solution to this, but very likely that would require some major changes to the code?

The company that I work for uses BIRT as a tool to dynamically generate PDFs, not so much reporting but more like filled out forms, letters and such. This works very well and is proof of the versatility of BIRT.
But because of our use case we have many different datasets spread out in different libraries.
If a dataset changes in one of the libraries, we have to manually step through all the reports that use a dataset from it and reset the bindings.
The suggested pass-through behaviour would be just plain awesome! :)

Just my 2 cents to let the developers know that people care about this. :)
BIRT is great so far!

PS:
Just for completeness: What I think what Paul Rogers meant when he said that implementing this in javascript is easy are getters and setters.
( http://ejohn.org/blog/javascript-getters-and-setters/ )
These are supported by Rhino and could contain the dataSetRow-access logic for the getters. So row["FOO"] could return dataSetRow["FOO"] if there are no overriding custom columns.