Subject Re: [IBO] Master-Detail dillemas with TIBO*
Author Eyal
Helen,

Thanks a lot for the very educative reply (as usual!)

> >So if I need to use a JOIN in the
> >future, then I should use TIBOQuery and lose the Master-Detail
> features.
>
> Why? TIBOQuery inherits the TQuery implementation of master-detail.
> Thus, like TQuery, it doesn't expose explicit MasterFields linking.
> This means that the linking columns in the two output sets must be
> of exactly the same type and have the same field names in the
> database; and the Details set must be designed so that the
> column[s] that link[s] to the Deal set's KeyLinks (for the
> masterlinking) are parameters.

I'm a bit lost here. Can you point me to an example, or a place in the
docs that explains this?

> Or perhaps you were unaware that you link your Details set to your
> Deal set through the Datasource property of the Details set?

Indeed...
I'll read IBO help again, but I'll appreciate a simple example.


> >2. Should I use cached updates? Before posting a deal to the DB I
> must check that the data is valid, eg. that the balance of all
>
> That sounds like an occasion when cached updates could be
> used.....However, since all posting is done at the level of the
> current row, you can always intervene in the BeforePost event of
> either (or both) dataset[s] to do this kind validation. The key
> thing here, where you have inter-row dependencies, is NOT to use
> an AutoCommit transaction.

I understand that I need to take control of the transaction, so that I
only commit once all the data is coherent. I don't understand how a
BeforePost can help me do validation that needs to check rows that the
user hasn't input yet.


> IMO, relying on client code to do this is not a good design
> practice, since it totally binds the integrity of your data to the
> application....and, if you have another application (maybe even in
> another language, which can't share your classes) you have to
> repeat the same validation.

I understand and even anticipated this shortcoming. But I don't really
have an alternative. I can't do all this server-side, becuause I need
to do validation and data fixing that depends on application parameters.

I don't want to waste too much of your time with detailed
explanations, but just some examples: I need to calculate a special
date field that depends on user input and a non-trivial logic, and
store the result in the detail row. Then I have to verify that all
those calculated dates in all detail rows fall within a certain range.
I need to calculate (and store) a tax amount field which depends on
many application variables and uses a very twisted logic (tax laws...)


> >4. When I try to input a new detail row I get an error box that
> >compains "missing value for MASTER_ID". I guess this is because
>
> You don't have the linking set up.
> ...
> The hidden implicit linking will take care of writing the
> master_id to the detail set when you call Insert on the detail set.

Ok, I think I'm starting to figure it out.


> >5. There are additional "missing value" messages for other fields.
> >Those are calculated fields, which can be calculated only after the
> >user inputs all data (ie. user click OK). How can I tell
> >TIBODataset to "be patient" with those fields until I actually
> >try to post?
>
> This needs to be explained more clearly. A calculated field on the
> client side doesn't exist in the database. It sounds as though you
> need some help constructing the detail query so you can get your
> head around the binding between the output set and the underlying
> table.

Those calculated fields that I mention are all "real" fields, ie.
columns in the table. As I explained above, I need to calculate them
client-side becuase the calculation isn't trivial. So during user
input those fields/columns don't have any values, because I fill them
only AFTER the user signals that input is done. However the user can't
input anything because the dataset complains on the missing values.

I may have found a solution. It seems that the dataset sets the
"Required" property for the TFields that correspond to each of those
columns. So I need to set "Required=FALSE" to prevent the dataset from
validating until posting time, at which point I'll take care of
stuffing the fields with the proper values.


> The methods that have to check the whole set will be pretty ugly,
> because they will have to iterate through the rows of the detail
> set....maintain a structure (TStrings usually) to hold the linkages
> between the detail set's Keylinks and the sequence number.

Can't I just iterate the rows in the dataset? Once the user is done
editing and before posting all the data, I can do eg.:
...
TotalCheck:=0;
VerifyOk:=VerifyMasterRow;
DetailQuery.First;
WHILE Ok AND (NOT DetailQuery.EOF) DO
BEGIN
Ok:=VerifyDetailRow;
CalcDetailFields;
TotalCheck:=TotalCheck+DetailQuery['amount'];
{ Etc. }
DetailQuery.Next;
END;
IF VerifyOk THEN
ApplyUpdates
ELSE
MessageDlg('Houston we have a problem');
...

> If the logic permits, call the set-level methods after the
> row-level validations are done.

I think I can do them both at the same time as shown in the example
above, ie. for each row do the validation and update the calculated
fields, and keep counters for set-level data.

At the end of the iteration I'll test the set-level counters, and
either proceed to post or warn the user to fix the input.


> >7. I want to let the user move detail rows relative to each other.
>
> Then you certainly want to cache the detail set. I think you will
> have to search for a third-party grid or tree control to get the
> UI you want, since the VCL's TDBGrid doesn't have the capability
> you want, AFAIR.

I'm not concerned about the UI part. I can add up/down arrow buttons
to move the current row, etc. Let's suppose I have the GUI in place -
how can I move a row in a (cached) dataset? I can't find any method
to change the order of rows, or to move a row from one "place" in the
dataset to another.

Helen - thanks again for the great help. I hope you still have some
more patience for me, as I now know that there's more I should know...

Eyal.