Commit changes wiith DBEdit lazarus / 16-Databases ---------------------------------------------------------------------- Edson · 2016-03-09 13:51 First of all, I'm not experienced using Databases in Lazarus, so probably I have concept problems. I have a TDBF and a TDataSource, used to connect to FoxPro tables. Then I used a TDBGrid and TDBEdit, to show the data. After connecting the Data-aware components I see this behaviour: - Modifying the DBGrid, modify the table, after closing connection. - Modifying the DBEdit DOES NOT, modify the table, after closing connection. How can I get to commit changes after modify DBEdit? How can I get a uniform behaviour, when modifiying data? Thanks. ---------------------------------------------------------------------- SymbolicFrank · 2016-03-09 14:06 Are you using a transaction? The following has to happen: DataSet.Edit; (Edit data) DataSet.Post; Transaction.Commit; You can use AutoEdit and AutoCommit, but in a relational database model, it is assumed that there are foreign keys and it is up to the programmer in what sequence changes are made. ---------------------------------------------------------------------- mangakissa · 2016-03-09 15:07 @SymbolicFrank Quote- Modifying the DBGrid, modify the table, after closing connection. - Modifying the DBEdit DOES NOT, modify the table, after closing connection. Transactions or not, if DBEdit has a fieldname and connected to a datasource, it still has to save all records after closing the dataset. But your right. It's better to do a commit after post. I'm curious the dataset.state is saying when the dbedit is left Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i if datasource.state in [dsEdit] then  showmessage('dbedit is modified'); ---------------------------------------------------------------------- Edson · 2016-03-09 16:59 My DBEdit is correctly connected to the Datasource, I guess, because it shows the value of the field (of the only row I have in  my table). But if I change the content of the DBEdit, and then close the connection, the changes are not saved. I need to do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin  Dbf1.Post;end; But if I do this, when no modifying the text, I get an exception  . ---------------------------------------------------------------------- vfclists · 2016-03-09 17:52 Quote from: Edson on March 09, 2016, 05:59:06 pmMy DBEdit is correctly connected to the Datasource, I guess, because it shows the value of the field (of the only row I have in  my table). But if I change the content of the DBEdit, and then close the connection, the changes are not saved. I need to do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin  Dbf1.Post;end; But if I do this, when no modifying the text, I get an exception  . Of course the dataset has to be in Insert/Append/Edit mode to be able to Post. ---------------------------------------------------------------------- Edson · 2016-03-09 18:29 Ok. I'm using this code, to accept the changes from the DBEdit: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   if Dbf1.State in [dsEdit] then Dbf1.Post;  It has sense. It let me discards changes no desired. But How can I have this same behaviour with a DBGrid?. It's let the user modify the content of the DBgrid, and only accept this changes, when doing: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Dbf1.Post; ---------------------------------------------------------------------- rvk · 2016-03-09 18:56 Quote from: Edson on March 09, 2016, 07:29:43 pmBut How can I have this same behaviour with a DBGrid?. It's let the user modify the content of the DBgrid, and only accept this changes, when doing: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Dbf1.Post; Actually, TDBGrid will automatically do a TDBGrid.DataSet.Post if you navigate to another record or away from the DBGrid. So there should be no need for a Dbf1.Post (if it all works correctly). You could do the Dbf1.Post (after checking if the dataset is in Edit-state) but it shouldn't be necessary. You could also put a TDBNavigator on our form to see what it all does (Buttons are grey when you can't post or when the post is already done automatically, etc.) ---------------------------------------------------------------------- Edson · 2016-03-09 19:20 I'm understanding. There is not a regular behaviour in differents Data-aware components. * DBGrid, decide when doing "Post", and it's not possible to change this. * DBEdit need the user do "Post", to save changes. So, If a need to have a Grid, with the ability for discard changes, DBGrid is not useful. ---------------------------------------------------------------------- rvk · 2016-03-09 19:30 Yes... because the DBGrid shows multiple records it needs to do a Post when you switch from one to the other record. For a DBEdit this is not the case. So, indeed, the TDBGrid is the only component which does an automatic Post. But you could do a Dataset.Cancel before there is a Post. For that create an event-procedure for your BeforePost of your dataset. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Table1BeforePost(DataSet: TDataSet);begin  if DataSet.State = dsedit then  begin    if MessageDlg('Data modified. ' +      'Would you like to save them before moving to other record?',      mtConfirmation, [mbYes, mbNo], 0, mbYes) <> mrYes then      DataSet.Cancel;  end;end;(Of course you could remove the confirmation prompt if you don't want it) But what is exactly your use? You could also make the Dataset readonly (or remove the UpdateSQL property). Or set the AutoEdit in the DataSource to false. In that case a user can't make changes. Why exactly do you want to cancel changes? If you use a DBNavigator on a form in combination with a DBGrid the user can press the Cancel- button on the navigator and his/her changes will be cancelled. Is that what you want? ---------------------------------------------------------------------- Edson · 2016-03-09 19:44 What I want to do, is to implement a Config Dialog, with the clasic buttons: "Cancel", "Apply", and "Accept". The values for this dialog, are read from a database. In this config dialog, the user could change any value, including the Grid (editing, adding or removing rows), but if he/she press Cancel, nothing must be change in the Database. ---------------------------------------------------------------------- rvk · 2016-03-09 20:06 Quote from: Edson on March 09, 2016, 08:44:30 pmWhat I want to do, is to implement a Config Dialog, with the clasic buttons: "Cancel", "Apply", and "Accept". Ah, and you want the user to change multiple values at once and still have the ability to cancel the whole (and all) changes? Then yes, DBGrid might not be the way to go. You might want to look into TValueListEditor (last one in the Additional tab). You could read all the settings in that component and once the user clicks Apply or Accept you could write all those values back to the database. When the user does nothing or clicks Cancel... you don't have to do anything. But it also kind of depends on the settings you have in your config on what component you would need. ---------------------------------------------------------------------- Edson · 2016-03-09 22:09 Yes, I want the user can discard all the changes. TValueListEditor just have a column, so I think it can not be useful, considering I have a table with 3 columns. Currently, I'm taking other solution. I'm using my library ConfigFrame: https://github.com/t-edson/ConfigFrame and intercepting the part where it access to a file, and redirect it to a my Database. ---------------------------------------------------------------------- taazz · 2016-03-09 22:32 Quote from: Edson on March 09, 2016, 11:09:04 pmYes, I want the user can discard all the changes. TValueListEditor just have a column, so I think it can not be useful, considering I have a table with 3 columns. Which dataset library you use? SQLDB supports cached updates which require you to call applyupdates in order to save the data to the server it also has a CancelUpdates method to undo all changes. ---------------------------------------------------------------------- Edson · 2016-03-09 22:53 Quote from: taazz on March 09, 2016, 11:32:34 pmWhich dataset library you use? SQLDB supports cached updates which require you to call applyupdates in order to save the data to the server it also has a CancelUpdates method to undo all changes. I'm using TDbf (http://wiki.freepascal.org/Lazarus_Tdbf_Tutorial) conected to FoxPro tables. I think this is a limited engine. ---------------------------------------------------------------------- mangakissa · 2016-03-10 09:35 I'm agreed with rvk. DBGrid is not the place to do this. I created a small demo for using DBEdits and Edits in a configdialog with the buttons you want. I hope it helps. ---------------------------------------------------------------------- SymbolicFrank · 2016-03-10 10:17 The easiest way to discard all changes at the end is by using TSQLTransaction.Rollback. ---------------------------------------------------------------------- rvk · 2016-03-10 15:01 Quote from: SymbolicFrank on March 10, 2016, 11:17:33 amThe easiest way to discard all changes at the end is by using TSQLTransaction.Rollback. That would be fine if the TDbf (which Edson, TS, uses) has a transaction-facility, but it doesn't. ---------------------------------------------------------------------- Edson · 2016-03-10 16:09 Quote from: mangakissa on March 10, 2016, 10:35:36 amI'm agreed with rvk. DBGrid is not the place to do this. I created a small demo for using DBEdits and Edits in a configdialog with the buttons you want. I hope it helps. Thanks @mangakissa, I'm going to study your code.    I think it will be very instructive. But I'm afraid, I need to modify a complete table (no only a row) and then, have the ability to discard or save all the changes. ---------------------------------------------------------------------- rvk · 2016-03-10 20:36 Quote from: Edson on March 10, 2016, 05:09:13 pmBut I'm afraid, I need to modify a complete table (no only a row) and then, have the ability to discard or save all the changes. I think the only option you have left, in that case, is using a TStringGrid (with goEditing in the Options). You can populate the StringGrid when entering the form en when the user wants to save the options you can write the rows to the database again. ---------------------------------------------------------------------- Edson · 2016-03-11 00:59 Yes. That's the way. Actually I'm following the same scheme I've used in my ConfigFrame library: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  +-----------+                  +-------------+                 +------------+ |           | ReadDBToProp()   |             |  PropToWindow() |            | |           | ---------------> |           | --------------> |            | |   DB      |                  | Properties  |                 |    Form    | |           | SavePropToDB()   |             |  WindowToProp() |            | |         | <--------------- |             | <-------------- |            | +-----------+                  +-------------+                 +------------+ ---------------------------------------------------------------------- mangakissa · 2016-03-11 08:11 That's easy to to use. But if you still want use a datalayer like DBGrid, memdataset or bufdataset is your answer. Offcourse you can build an own class to hold the properties of your form.