0

I have been having some issues with using Disable/EnableControls() while iterating over a DataSet, namely when updating field(s).

What seems to be happening to the two updated fields, is that they are all taking the same data. It looks like the last value for the post is being entered for all rows. So lets say we have 3 records, that have updated values of 1, 2 and 3 (in my case, 3 is being posted for all fields) when I was expecting 1, 2 and then 3 for the last field.

For example, I have 10 records that are in my dataset. I run this function, upon looking at the grid, and persisting data the Cost column value is the same for each row, even though I have stepped through and put a watch on the getNewDataValue function, and they are different values.

NumberSelected = 0;
dataSourceItems.DataSet.DisableControls; //it this be my problem, accessing the dataset via the datasource? – I tried this and it didn’t make a difference.
while (NumberSelected < cxGridDBTableView1.Controller.SelectedRowCount) do
begin
  Id = cxGridDBTableView1.Controller.SelectedRows[NoSelected]).Values[0];
  if dataSourceItems.DataSet.locate('PK', Id, []) then 
  begin
    dataSourceItems.DataSet.edit;
    dataSourceItems.DataSet.fieldbyname('Cost').asfloat := getNewDataValue;
    dataSourceItems.DataSet.Post;
    inc(NumberSelected)
  end;

  dataSourceItems.DataSet.EnableControls;
end;

I am using Delphi 2010, DevExpress Quantum Grid, and FIBPlus datasets, accessing a Firebird database.

Looking over the documentation, I can see that when DisableControls() is called, TDataSet.DataEvent doesn't pass events to DataSources, and that all master detail relationships are broken, until EnableControls() is called. Could it be that I am accessing the DataSet on the DataModule via the DataSource? I have tried this, and it doesn't make a difference.

Without using Disable/EnableControls(), the speed is unusable. So any advice, or alternative way of iterating over a large DataSet at speed, would be helpful.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
MrRobot
  • 169
  • 3
  • 10
  • You should not rely (as you are at the moment) on the change being posted to the dataset before its row-cursor is moved. Explicitly call dataSourceItems.DataSet.Post immediately after your fieldbyname() assignment. Try that - it may solve you problem by itself, but you should be doing it anyway. – MartynA Aug 15 '16 at 21:58
  • Edited my question for clarity, as I didn't actually put the call to post explicitly. Your right, I will change and test now. – MrRobot Aug 15 '16 at 22:04
  • Get the same result even after posting immediately after the fieldbyname() assignment. – MrRobot Aug 15 '16 at 22:08
  • Did you put a watch on you 'Id' value and ensure it's changing, and that all rows being updated have a different Id value? – John Easley Aug 15 '16 at 22:16
  • 1
    Btw, the least error-prone way to do this is to build a list if selected-row IDs, then temporarily disconnect your dataset entirely from the cxGrid while you process the selected rows. That **will** work. – MartynA Aug 15 '16 at 22:49
  • 1
    Disable/EnableControls does not affect whether the data is posted or not, or whether the dataset receives any assigned events. It only affects whether controls attached to it's fields are updated or not (IOW, it only affects the UI). I've used data-aware controls for decades (literally) and never had an issue with DisableControls interfering with the data being properly updated and saved. What I suspect you've encountered is a bug in the cxGrid - I see it regularly in the Advantage Data Utility (ARC32), which uses the grid. If you execute a query, set the focus on the grid, and scroll rapidly, – Ken White Aug 15 '16 at 22:51
  • 1
    (continued) it appears that the grid contains many repeated rows. (It sometimes appears that all the rows are the same.) When you stop scrolling, the display catches up and the proper rows are displayed. As this only happens in ARC32, and I can't get it to happen with the same data and query using a standard DBGrid, I'm certain the issue is with the cxGrid. – Ken White Aug 15 '16 at 22:56

1 Answers1

4

You are calling EnableControls() from inside the loop, when it should be outside the loop instead (preferably in a try..finally block).

But more importantly, you are not incrementing NoSelected, so you are always accessing the same selected ID each time you make an edit. You have two variables fighting to doing the job that one variable should be doing by itself.

Try this instead:

NumberSelected = 0;
dataSourceItems.DataSet.DisableControls;
try
  while (NumberSelected < cxGridDBTableView1.Controller.SelectedRowCount) do
  begin
    Id = cxGridDBTableView1.Controller.SelectedRows[NumberSelected]).Values[0];
    if dataSourceItems.DataSet.Locate('PK', Id, []) then 
    begin
      dataSourceItems.DataSet.Edit;
      dataSourceItems.DataSet.FieldByName('Cost').AsFloat := getNewDataValue;
      dataSourceItems.DataSet.Post;
    end;
    Inc(NumberSelected);
  end;
finally
  dataSourceItems.DataSet.EnableControls;
end;

Alternatively:

dataSourceItems.DataSet.DisableControls;
try
  for NumberSelected = 0 to cxGridDBTableView1.Controller.SelectedRowCount-1 do
  begin
    Id = cxGridDBTableView1.Controller.SelectedRows[NumberSelected]).Values[0];
    if dataSourceItems.DataSet.Locate('PK', Id, []) then 
    begin
      dataSourceItems.DataSet.Edit;
      dataSourceItems.DataSet.FieldByName('Cost').AsFloat := getNewDataValue;
      dataSourceItems.DataSet.Post;
    end;
  end;
finally
  dataSourceItems.DataSet.EnableControls;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770