Recent

Author Topic: [SOLVED] How to manage the order of creation of the components in a datamodule  (Read 1553 times)

devEric69

  • Hero Member
  • *****
  • Posts: 648
Hello,

When I have two datasets, with a calculated field in the second dataset depending on the first dataset, is there a way to manage the order of creation of the components in a datamodule, (or should I modify their creation order by editing the *.dfm file)?
« Last Edit: July 13, 2019, 02:13:44 pm by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
I'm not completely sure whether it really matters or not but when I have that kind of problem, for example in forms with several controls aligned to the same side which get added in the wrong order, I do indeed edit the .lfm and put them in the "correct" order.

As an extra measure I also sort them in the source file, although I'm sure that doesn't matter at all. :)

Now, whether this also applies to datamodules ... I've no idea. It probably does.

ETA: Of course, the other way I know of to ensure they get created in the correct order is to do it in code. No question then of Who's first and What's second :D
« Last Edit: June 22, 2019, 12:03:01 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

devEric69

  • Hero Member
  • *****
  • Posts: 648
All right.

Thank you for the answer (the order of creation can sometimes play a blocking role in Delphi, especially with calculated fields - statically created - and master-detail relationships, at the time of the Open: it is better to create dependencies first, and dependants last, to be "quiet".
It was just to know, if I had missed an option from the environment or elsewhere, preventing me from displaying a hypothetical  "re-ordering window", managing this order of creation of statically created components at design time.
==> Editing the *.dfm is fine with me  :) )
.

use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

devEric69

  • Hero Member
  • *****
  • Posts: 648
nb: this kind of window exists, at least, for the statically created fields, of the "IBX" dataset components, which I currently use.
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

devEric69

  • Hero Member
  • *****
  • Posts: 648
(I complete by an example, the usefulness of knowing that we can play, with the order in which the components are created)

I take an example of a master-details relationship composed with 2 IBX components TIBDataset for Firebird (using a datasource property), to explain this use:

I have a Firebird table TRIGGERS whose schema is:
Code: SQL  [Select][+][-]
  1. TRIGGER_PER_DIRECTORY_ID, -- primary key
  2. PATH_CLIENT_TRIGGER,
  3. PARAMETERS,
  4. IS_ACTIVE,
  5. DIRECTORY_ID -- foreign key

So, assuming that the order of creation of the dataset's TFields collection - what is called the TFields definition in Lazarus or the TFieldDefs in Delphi - follows the same order as that displayed in Firebird \ FlameRobin \ IBeasy \... I wrote:

Code: Pascal  [Select][+][-]
  1. dtsTriggersDetailsByDir_rw.AppendRecord([nil, edtDir.text, '  ', 0, dtsDirsMaster_rw.FieldByName('DIRECTORY_ID').AsInteger]);

==> I get a laconic message " '  ' " is not a valid integer" (btw, these too succinct messages will be more complete in a future version of Laz\FPC: they will indicate the name of the field in question). The conclusion is therefore, that I pass an order of values - to append - which does not follow - in fact - the order of the original schema of the physical SQL table. Which was my presupposition.

To get around this problem, there are 2 solutions:
- do not rely on the TFields collection dynamically created by Lazarus at each dataset creation, but create your own TFields collection of persistent dataset fields and order them in the order you want to immutable, i.e. this fields collection's order will be respected at each re-creation of the dataset-TIBdataset (typically: the persistent order chosen could be the same as the order of the fields, such as it is in the physical SQL table; Cf. the screen shots).
- use the Append method and sets each value in its named field:
Code: Pascal  [Select][+][-]
  1. with dtsTriggersDetailsByDir_rw do begin
  2.     Append;
  3.     FieldByName('PATH_CLIENT_TRIGGER').AsString:= edtPathClientTrigger.Text;
  4.     FieldByName('PARAMETERS').AsString:= ' ';
  5.     FieldByName('IS_ACTIVE').AsString:= 0;
  6.     FieldByName('DIRECTORY_ID').AsInteger:= dtsDirsMaster_rw.FieldByName('DIRECTORY_ID').AsInteger;
  7.     Post;
  8. end;

nb: the TRIGGER_PER_DIRECTORY_ID field - the primary key - is affected by its generator.

➔ This will work all the time, without the need to create an ordered TFields collection of persistent fields, if one is not intransigent about an imperative existence of a personal order with the TFields collection of the dataset (also called TFields definition).


« Last Edit: July 12, 2019, 03:51:37 pm by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

tonyw

  • Sr. Member
  • ****
  • Posts: 319
    • MWA Software
I believe that you have two (connected) issues here. The first is on the use of TDataSet.AppendRecord and the second is on the order of field creation.

I would only normally recommend the use of AppendRecord for simple datasets with only a small number of columns and where insert performance is an issue. As you have observed, AppendRecord depends totally on the programmer knowing correctly the field order and, if you get that wrong, or the field order changes, the result is difficult to resolve bugs. This can happen because of type incompatibility or, even worse, data being assigned to the wrong field. Data is also assigned as a variant type, which can also lead to unexpected behaviour in some cases.

The internal implementation of AppendRecord is all in TDataset and not part of IBX or any other database provider. One of the problems with it  is that the exceptions reported do not include the field name and again, it becomes difficult to determine which value was type incompatible. The problem you reported is on line 1534 of the source file "field.inc" in the FCL, and you can clearly see here where the error is raised without a field name (although it is known at this point). If you want to raise a defect report then the defect is in the Free Pascal FCL rather than Lazarus.

The second issue is on field creation order. If you do not create persistent fields (e.g. by adding them to the DataModule/Form at design time) then the fields are created dynamically at run time. IBX is deterministic in respect of the order in which the fields are created. It creates them in select query order - my guess is that the other database providers do the same.

The reason for select query order is that the TDataset model is that of a table populated from the database query and any computed fields that you define. The primary source is thus the select query. When you add rows or update a row, the field order is already determined. An Insert or an Update query is used to write the new/updated values back to the database, but the order of the fields in either query is allowed to be different to the field order in the TDataset itself. Under IBX, the convention is used that the query parameter names are the same as the column names, and IBX associates the query fields this way rather than by position.

In your example, you appear to be assuming AppendRecord field order is the same as the insert query and that  I guess is where your problem started.

 

TinyPortal © 2005-2018