Delete row from DBGrid only - delphi

I have a DBGrid that is updated on a button click. Once updated I have it check each row vs an XML file. If the fields in that row match the data in the XML file, I want to delete that row from the dbgrid only.
The DBgrid is loaded from ADOconnection / Query / Datasource . The main connection is to a DB which is linked to an excel file. The XML file is just a report we get each month. Normally we have to check to make sure all the machines on the excel file is also on the report given to us.. With hundreds of machines I am trying to auto detect any difference.
but I cant figure out how to delete the row in the grid only when it finds a match Thus only the non-Matched items are in the grid.

You can't delete rows from a DBGrid. You delete them from the dataset to which the DBGrid is connected. A DBGrid simply displays the data from a dataset. If you want the row deleted, delete it from that dataset using it's .Delete method.
After reading the edit you made, it looks to me like you should be loading the query data into a TClientDataSet (CDS), and then attaching that CDS to the DBGrid's DataSource. You can then do whatever you want to that CDS without affecting the original data, as long as you don't call the CDS's ApplyUpdates method.

What Ken White says in his answer is 100% correct, but I think there is something else
maybe worth pointing out, especially as you mention XML.
Unlike some other TDataSet descendants, both TClientDataSet and the more modern FireDAC datasets implement the UpdateStatus
property of the dataset and this reflects what has happened to the current record
in the dataset - see the Online Help for details. It is an enumeration [1] declared as
type
TUpdateStatus = (usUnmodified, usModified, usInserted, usDeleted);
You say you want to compare the records with what you have in an XML file and delete
the records which have not been updated "from the DBGrid", which as Ken has said is
not meaningful per se.
However there is another way of going about what you seem to want. If you can load the
data displayed in the dataset feeding the grid from the XML file. then you know
that until you update the dataset, the records must match the XML. So, once the
records have been updated in your app, rather than comparing all the records in the dataset
with their XML counterparts, you could simply delete (from the dataset) the records
whose UpdateStatus is usUnmodified. This is trivial to do using a method like this:
procedure TForm1.DeleteUnmodifiedRecords;
begin
ClientDataSet1.DisableControls;
try
ClientDataSet1.First;
while not ClientDataSet1.Eof do begin
if ClientDataSet1.UpdateStatus = usUnModified then
ClientDataSet1.Delete
else
ClientDataSet1.Next;
end;
finally
ClientDataSet1.EnableControls;
end;
end;
and this will, of course, remove the records from the DBGrid.
Of course, this assumes that you can load the XML data into a TClientDataSet
or a FireDAC dataset, eithe directly or by transforming the XML into a form that
either of these can load using a TXmlTransform component but I won't go
into the details of that here.
[1]: A point to beware of is that usModified does not seem to be the exact logical negation of usUnmodified. This has the slightly surprising consequence that if you
apply a StatusFilter of [usModified] to a CDS, records that have been changed can appear twice, once in their original form and once in their changed form - see fig 6.5 of Cary Jensen's "Delphi in Depth: ClientDataSets", 1st edition.

One option to make rows/records vanish from a dbGrid and other data aware controls is to use the TDataSet's OnFilterRecord and return false for rows you no longer want seen. It does not have any effect on the underlying data - it just filters out what is visible.
procedure TDM1.FDQueryTopicListFilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
// Check if the row should be shown - set Accept to true if it should, false if not
end;

Related

TAggregateField not calculated when Index of ClientDataset changes

I am using a TClientDataset, connected to a DBGrid, with a couple of Aggregate Fields, for calculating the SUM of an other couple of Float Fields. All fields have been created in Design time.
Everything is working as expected, until the time that the IndexName of the ClientDataset changes with a custom Index, in order to sort the Grid. After that, the Aggregate Fields don't calculate their value properly, and they are set with Null value.
The problem occurs in Delphi XE7.
I have google about it and i found a solution that worked for me here
There is a bug at TCustomClientDataSet.SetIndex method that is declared in the DBClient unit.
The solution propose to replace the following code
if FAggregatesActive then
begin
FAggFieldsInit := False;
ResetAllAggs(FAggregatesActive);
with the next one
if FAggregatesActive then
begin
CloseAggs;
ResetAllAggs(FAggregatesActive);
As far as i understand, the replacement of FAggFieldsInit := False with CloseAggs, force the Aggregates to be released and then recalculate with the new index.
As i said this solution worked for me, and i haven't notice any unwanted behavior.
The credit goes to AndreyZ for the original solution.

Delphi DBGrid not showing data

I have a delphi form with TFDConnection, TFDQuery, TDataSource and TDBGrid. I want to show the data that my query gets (select * from table_1) and put it in my DBGrid.
I've made all the connections between the components, but after I launch my query (which returns 12 rows) in my DBGrid are shown 12 rows but they are empty. Apparentely I forgot something that prevents me from seeing my data in my DBGrid. Can you help me what I'm missing in my actions ?
1- Adding all components to the form.
2- Connect FDQuery with FDConnection, TDataSource with FDQuery, DBGrid with TDataSource.
3- Connection parameters succed in testing (the problem is not in my connection parameters)
4- The number of rows are placed in my DBGrid (12), but with no information visible.
5- If I loop through my FDQuery I can see all the information I need but that doesn't help me populate my DBGrid.
Can you try this:
Make your TFDQuery active explicitly in your OnShow code of your Form. Like this,
procedure TForm.FormShow(Sender: TObject);
begin
FDQuery.Active:= True;
end;
It works for me and hope it helps.
You would get the behaviour that you would see the correct number of rows in the DBGrid, but the grid's cells are empty, if the DBGrid's DefaultDrawing property is set to False. if that's the case for your DBGrid, obviously just set DefaultDrawing to True.
To fix this problem (which I had the same), after you open the query, set:
datasource.dataset := Query
and the problem will be resolved.
I know the topic is old, but maybe it can help someone. In my case, the solution was: Deleting all the DBGrid columns that was created in design time, OR match the column's (TColumn) FieldName property to the EXACT field names as they named in the database tables.
For anyone else with this problem, here's the fix: make sure that the column names (not the Title) in the grid control match the field names in the query. Once they're matched they should behave properly.

Using bookmarks with filtered query

I need help with the following problem. I have a dbgrid, the underlying query is filtered. I want to apply a new filter but stay at the same row number in the dbgrid. Here is my code:
with qrProperties do
begin
...
MyPoint:=GetBookmark;
Filter:='N<>'+IntToStr(ResultPropertyN);
Filtered:=True;
GotoBookmark(MyPoint);
end;
When it gets executed, an EDBEngineError is raised with a message "Could not find record". My explanation is that the bookmark functions do not take into account the filter and the procedure GotoBookmark searches for a record that is not present in the dbgrid (due to the filter applied). Is there any way to use bookmarks with filters?
Here are a little more details. In my application when I double click on a row in the dbgrid, it disappears (due to the filter applied) but as a result of the filtering the cursor moves to the first row (if I do not use bookmarks). I want it to stay at the same row number that is to go to the record shown immediately after the one that has been deleted.
Your assumption is correct, the record is no longer 'there'.
Wrap GotoBookmark in a try/except and decide what to do in the exception, e.g. go to the first record.
Alternatively you could go to the 'nearest' record you can find. That depends on what you consider 'nearest' and then you would not need bookmarks at all and use e.g. FindNearest.

Delphi 2007 Unable to modify the data in beforescroll event using source code, Error: Dataset not in Edit or Insert Mode

A bit of History:
I have a DBlistbox containing textt descriptions and I store just the codes of this in a mysql table which is displayed in a dbgrid. User can select multiple options and I like to process these and store as comma separated values in one of the columns (this column is invisible in the dbgrid).
Right now I can populate the listbox when the user scroll through the dbgrid using event Afterscroll and Formcreate. But when I try to process the list and update the myquery behind the dbrgid I get an error saying 'Dataset not in Edit or Insert mode' - I do this in beforescroll
Please help!!
I have tried to set the dataset to edit mode before changing then as soon the data is posted dbgrid seems to have funny characters
If I got you right, the DBListBox is not connected to the dataset lonked in the grid? This would explain why the grid's dataset is not set to edit mode when you change the data in the DBListBox.
Anyway, whenever you change data that has to go into the mysql table, you should switch this dataset into edit mode. Then you can place your coding of the comma separated values into the OnBeforePost event.
When the dataset scrolls without any change in the data of the listbox, there is no need to store any data. This is achieved with the above approach as without edit mode no BeforePost event will fire in this case.

Benefit of using DBComboBox over CombBox?

So I'm messing around with a new project in Delphi 2009 and the default components that can be dropped onto a form for accessing data consist of a SQLConnection, DataSource and SQLQuery. If I add a simple select to the query component, say:
select name from customers
and then drop a DBComboBox on the form and link it up with the DataSource I get a single record in the combo box. After using Google for half and hour to figure out what I was doing wrong it looks like you have to manually add some code to your project which loops through the dataset and adds all the records to the drop down box. Something like:
while not SQLQuery.eof do
begin
DBComboBox.items.add(SQLQuery.fieldbyname('name').asstring);
SQLQuery.next;
end;
And that actually sort of works, but then you get a list in the drop down which you can't actually select anything from. Regardless of the result though I'm wondering why would you even use a DBComboBox if you have to manually add the result of your query to it? Seems to me that if it doesn't automatically populate the db combo box with the result of the query then we might as well be using a non-data-aware component like tcombobox.
I guess what I'm asking is why does it work this way? Isn't the purpose of data aware drag-and-drop controls to minimize the amount of actual written code and speed development? Is there a method that I'm missing that is supposed to make this easier?
A TDBComboBox doesn't get its list of values from the database; it gets its current value from the database. Link it to a field in your dataset, and when you change the active record, the combo box's current value will change. Change the combo box's current value, and the corresponding field's value will change.
If you want to get the list of values from the database as well, then use a TDBLookupComboBox.
This is all covered in the help:
Using TDBListBox and TDBComboBox
Displaying and Editing Data in Lookup List and Combo Boxes
Defining a Lookup List Column
I think you want the TDBLookupComboBox because that allows you to lookup from a list of items where the list comes from a dataset.
In the TDBComboBox, the list is just a TStrings manually filled with data.
--jeroen
DbCombox is a dbaware version of the standard combobox component.

Resources