Subject Re: [IBO] Unusual behaviour IB_Grid
Author Helen Borrie

There are a few problems here.

First of all, take the complications out of your life and use
GeneratorLinks to get the value for the new row.

Next, don't put data substitution/validation code on bar button clicks or
any other methods of controls. Use the methods of the dataset to do
that. IBO *by design* makes all the interesting stuff happen in datasets,
independently of the controls.

Next, understand the timing of events. ALL DML operations have a Post
event, *including* inserts. Post is the very first dataset event (other
than the original SELECT, of course) that actually touches the
server. BeforeSomething and AfterSomething are dataset events. So, as a
rule, put data transformations, validations, et al. in the BeforePost event
of the DATASET.

Instead of me (or someone else) spending time picking your code apart and
explaining blow-by-blow why this or that thing is going to get missed,
revisit the whole thing yourself and address your interventions as things
to do to the current row of the dataset before its Post method gets called
(by whatever means).

And, repeat, use GeneratorLinks. They are totally transparent,
encapsulated right in the dataset's "to-do list" when Insert is
called. You don't need to test whether the dataset is in the right update
mode at all.

Oh, and "lost" inserts (and usually updates and deletes as well) can
usually be tracked to bad KeyLinks.


At 12:18 PM 20/06/2004 +0200, you wrote:
>Dear All / Jason
>Hope you can help me. Last posted 2004/05/17
>I've been struggling with this one ever since.
>I'm sending it in private to Jason as well. Hope he can help. (Please
>Jason .. Help me with this one PLEEEESE)
>I've added code from a test app below.
>I'm using a generator for the ID field of a table, and I'm using before,
>and after events to assign the ID field.
>See the source below.
>NB! NB! NB!
>If I don't use before event, but enter the ID physically, then all works
>just fine!!
>So then I narrowed it down to actually assigning the ID field to the
>When that is done, the last column's data on the grid is lost.
>So, I can only assume that once I have entered the last column in the
>grid, then click post, the before event is fired, then the ID field is
>assigned to the Query, then the data is lost in the grid.
>Here is the description of what is happening as originally posted
>I've an IB_Grid, a IB_UpdateBar, and a IB_Query.
>When I display data on the grid, and insert a new record, I then type
>the data in on the collums on the grid.
>The last collum I enter data into, is not moved out of, and I then click
>the post button.
>The record is posted to the grid, but the data entered in the last
>column is not posted, it is left <NULL>. (Does not have to be a specific
>column, any column that is not tabbed out of.)
>If I then edit the record, and reenter the data for the column, it then
>posts it correctly.
>If I enter data for the column on an insert, and then move out of the
>column to the say previous column, same row, and then post the data, it
>is then accepted, and shows.
>Why on earth must I first tab out of the column to get the data to be
>Surely I can enter the data for the column, and then just click on the
>post button.
>Please all help will be appreciated.
>Source code:
>unit test_IB_Grid;
> Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
> Dialogs, IB_Components, IB_ConnectionBar, IB_NavigationBar, ExtCtrls,
> IB_UpdateBar, Grids, IB_Grid, IB_StoredProc;
> TForm1 = class(TForm)
> IB_Grid1: TIB_Grid;
> IB_UpdateBarPERFORMANCE: TIB_UpdateBar;
> IB_NavigationBar1: TIB_NavigationBar;
> IB_ConnectionBar1: TIB_ConnectionBar;
> IB_Database1: TIB_Database;
> IB_DataSource1: TIB_DataSource;
> PROCGetNewId: TIB_StoredProc;
> function GetNewID(const aTable: String): Integer;
> procedure IB_ConnectionBar1AfterAction(Sender: TObject);
> procedure IB_UpdateBarPERFORMANCEBeforeAction(Sender: TObject);
> procedure IB_UpdateBarPERFORMANCEAfterAction(Sender: TObject);
> private
> { Private declarations }
> public
> { Public declarations }
> end;
> Form1: TForm1;
>{$R *.dfm}
>NewPERFID: boolean;
>IPERFID: integer;
>procedure TForm1.IB_ConnectionBar1AfterAction(Sender: TObject);
>IB_QueryPERFORMANCE.Active := True;
>procedure TForm1.IB_UpdateBarPERFORMANCEAfterAction(Sender: TObject);
>If (IB_UpdatebarPerformance.FocusedButton = ubInsert) then
>NewPERFID := True
>If (IB_UpdatebarPerformance.FocusedButton = ubPost) or
>(IB_UpdatebarPerformance.FocusedButton = ubCancel)then
> begin
> IF (IB_UpdatebarPerformance.FocusedButton = ubPost) then
> begin
> IPERFId :=
> NewPERFId := False;
> end
> end
>NewPERFId := False;
>procedure TForm1.IB_UpdateBarPERFORMANCEBeforeAction(Sender: TObject);
>If (IB_UpdatebarPERFORMANCE.FocusedButton = ubPost) And NewPERFId then
> begin
> When this line is executed, then the last column not tabbed out
>of is lost!
> end
>Else If (IB_UpdatebarPERFORMANCE.FocusedButton = ubEdit) then
> {This line is entered so that if click on text to edit without
>first placing in
> edit state will still secure the PERFORMANCEID to return to the record
>after the post}
>Else If IB_QueryPERFORMANCE.State = dssEdit then
>function TForm1.GetNewID(const aTable: String): Integer;
>{ call the stored procedure to get a new ID }
>PROCGETNEWID.ParamByName('TABLENAME').AsString := AnsiUpperCase(aTable);
>Result := PROCGETNEWID.FieldByName('NEW_ID').AsInteger;
>Jason .. should I not be using before after events with a generator to
>assign incremental Id fields in my tables.
>Is there a more elegant method.
>I don't want to redesign my entire application.
>Thanks for all help!!!!!!!!!!!!!!!!
>[Non-text portions of this message have been removed]
>IB Objects - direct, complete, custom connectivity to Firebird or InterBase
> without the need for BDE, ODBC or any other layer.
> - your IBO community resource for Tech Info papers,
>keyword-searchable FAQ, community code contributions and more !
>Yahoo! Groups Links