Refreshing a detail TDADataTable doesn't re-open if the Master table state is dsEdit

tdadatatable
masterdetail
delphi

(Stuart Clennett) #1

Hi,

I have a detail table that I need to refresh independently of the master table; I’m using the close/open method.

If the master table is in dsEdit mode the detail table will not open, but the AfterOpen event is still called. This causes issues with any AfterOpen event handlers that (correctly) assume the table will be open.

There is a line in your code that says “If Master.State = dsBrowse” then … and it proceeds to open the table.

Either allow the table to be opened in dsEdit mode as well, or ensure that the after-open event isn’t called and there’s some warning to the developer…?

(mappingmode = mmWhere, detail and masteroptions are all default)

Thanks

DA 9.3.105.1337
Delphi 10.1 Berlin


(EvgenyK) #2

try to use detail.RefreshFromServer instead of Close/Open.
will it work as expected?


(Stuart Clennett) #3

Okay, that seemed to work… BUT

I am also using the Detail table as the source of a cloned datatable. When I refresh the detail table, the cloned table loses the master-detail link.

Example:

  • Detail table links to Master Patient table by Patient ID.
  • Detail table has ~50 records.
  • Open a new form with Clone.Clonesource = Detail.
  • Clone now has the same 50 records as expected
  • Refresh the new form using “Clone.Clonesource.RefreshFromServer”
  • Detail table still has the correct ~50 records,
  • … but Clone now has ALL records in the table (approx 3.7k).

Any ideas?


(EvgenyK) #4

as designed. cloned tables works with original (i.e. not filtered) record set so it is a reason why cloned table contains all records.
also it is possible to use cloned tables as detail tables with different masters

as a workaround, you should filter records, i.e. specify mastersource as it was used in detail table.


(Stuart Clennett) #5

Ok, thanks for the information.

Cheers


(Stuart Clennett) #6

Hi Evegeny,

I tried to implement your solution as follows:

MasterTable --> DataSource1 --> DetailTable
MasterTable --> DataSource2 --> DetailTableClone (CloneSource = DetailTable)

And I am getting the following error when creating my datamodule:

exception class   : EAccessViolation
exception message : Access violation at address FFFFFFFF. Read of address FFFFFFFF.

main thread ($778):
ffffffff ???

main thread ($778), inner exception level 1:
>> EStringListError, String list does not allow duplicates
System.Classes                 TStringList.AddObject
uDADataTable          6157  +8 TDADataTableRules.RefreshDetails
uDADataTable          6040  +1 TDADataTableRules.Attach
uDADataTable          2257  +2 TDADataTable.Loaded
System.Classes                 NotifyGlobalLoading
System.Classes                 InitInheritedComponent
System.Classes                 TDataModule.Create

DetailTable and CloneDetailTable (obviously) have the same LogicalName.

Any ideas?

Thanks


(EvgenyK) #7

can you create a simple testcase that reproduces this situation, pls?


(Stuart Clennett) #8

DemoServerAndClient.zip (524.8 KB)

Here you go. You’ll need to adjust the path of the database file in the ConnectionManager.

When I start this project I get this:

exception class    : EStringListError
exception message  : String list does not allow duplicates.

main thread ($b58):
00523f3b +43 DemoServerClient.exe System.Classes           TStringList.AddObject
0085f59d +a9 DemoServerClient.exe uDADataTable     6157 +8 TDADataTableRules.RefreshDetails
0085f34f +0f DemoServerClient.exe uDADataTable     6040 +1 TDADataTableRules.Attach
008533d5 +29 DemoServerClient.exe uDADataTable     2257 +2 TDADataTable.Loaded
0051f607 +2b DemoServerClient.exe System.Classes           NotifyGlobalLoading
0051f78e +7e DemoServerClient.exe System.Classes           InitInheritedComponent
005379bc +78 DemoServerClient.exe System.Classes           TDataModule.Create
0066992e +76 DemoServerClient.exe Vcl.Forms                TApplication.CreateForm
00a2f61f +2f DemoServerClient.exe DemoServerClient   20 +2 initialization
76548652 +22 KERNEL32.DLL                                  BaseThreadInitThunk

It would appear that it doesn’t like two detail tables for the same master table with the same LogicalName.

Thanks.


(EvgenyK) #9

Thx for testcase.
I can reproduce this case and it is related to TDADataTableRules.

unfortunately, TDADataTableRules disallows to use the detail tables with the same name because logic of these methods will be incorrect:

    function FindDetail(const aLogicalName : string) : TDADataTable;
    function DetailByName(const aLogicalName : string) : TDADataTable;

I can suggest to you just set LogicalName for cloned table as unique name (like VALIDATION_ERRORS_clone1) because LogicalName for cloned tables is useless because cloned tables share a record set with table from that they were cloned.


(Stuart Clennett) #10

Thanks.

I’ve just tried using the following:

clone_VALIDATION_ERRORS.RefreshFromServer;

and I get

 Cannot find item "VALIDATION_ERRORS_clone1" in collection of type TDAServerDatasetCollection.

If I want to refresh both detail tables; can I just refresh the original and the clone will get refreshed too?

Thanks


(EvgenyK) #11

you should call method of original table (not cloned one):

tbl_VALIDATION_ERRORS.RefreshFromServer;

cloned table always uses the record set of original table.


(Stuart Clennett) #12

Great - thanks for your help :slight_smile: