[Solved] SQLDB and MVC... lazarus / 16-Databases ---------------------------------------------------------------------- gelinp · 2016-04-14 07:05 Good morning ! I've got a form a liitle bit complex, with only one database connexion (and one transaction). This form is made of : * 2 readonly Datasets (list selectors) ; * 3 Edit datasets (depending from the 2 firsts  thanks to  datasources connexions). 1. I tested with only one database connexion and it was OK, but when I commit one of the 3 edit datasets there is a reset of all Datasets so I have to save bookmarks then open all 5 datasets and refresh the interface... It's a little bit complicated... So I was looking for a secpond maner... 2. I tested to use 2 databases connexions (and 2 transactions), one for the first 2 datasets readonly and the second for the last 3 datasets in edit mode. But I've got a problem : my first Edit Dataset use a paremter connected to the first datasource of the readonly dataset,  and the connexion dosn't run.... and then the edit interface stay empty ! So what do you suggest to make MVC suitable with SQLDB and complex forms ? Thank you for your help ! ---------------------------------------------------------------------- SymbolicFrank · 2016-04-14 12:39 Yes, that's how it works. The easiest way is using the events of the datasets, like AfterUpdate, and setting the parameters for the other sets. I tend to make a procedure that sets a bookmark, closes all the datasets, opens the first one, goes to the bookmark, fills in the parameter(s) for the second one, opens that, fills in the parameters for the third one, open that, etc. ---------------------------------------------------------------------- gelinp · 2016-04-14 14:28 Yes you do, I'm very interested to download your procedure if you share it    I suggest you to make a MasterDetail object to encapsulate it and connecte each one to an other. I will try myself to do it... My problem now is that the my commit doesn't work, I understand this due to the applyupdate which crash the application, but I can't know why... I verified there is Edit mode activated, and all is active... At this time I'm debugging again ... ---------------------------------------------------------------------- SymbolicFrank · 2016-04-14 15:15 Such a procedure is very application-specific, so I don't have a default one. The reason I do it like that is, that it prevents problems like you have, by having a lot of events that all try to "fix" things. The master is where you set the bookmark, all the children is where you set the parameters. ---------------------------------------------------------------------- gelinp · 2016-04-19 14:41 I'm asking myself is my algorithm is good to update. I understanded it was something like that (short resume): qyupdate = TZQuery.Create(nil); qyupdate.datasource := DS; qyupdate.SQL.text := 'SELECT ...' qyupdate.edit; {Fields affectations...} qyupdate.applyupdate; transaction.commit; But this shema failed with a database error message on applyupdate... I 'm reading the book "Getting Started with Lazarus and Free PAscal" explaining an other solution, like that : qyupdate = TZQuery.Create(nil); qyupdate.datasource := DS; qyupdate.SQL.text := 'SELECT ...' qyupdate.Insert; {Fields affectations...} qyupdate.Updaterecord; Post; I don't understand why first schema is wrong ? ---------------------------------------------------------------------- mangakissa · 2016-04-20 07:33 You can't use applyupdates if the dataset is in edit mode. First use post(). This tells tbufdataset there's a record to be updated end create an query to update the record in your table. ---------------------------------------------------------------------- gelinp · 2016-04-20 08:19 Ok, so now my code is like that : 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 TFormMain.EnregistrerClick(Sender: TObject);var  CurID : Integer;begin  if (DataModule1.SQLDetailSeances.Active) then  begin  CurID := SaveRecord(DataModule1.SQLDetailSeances, 'PKseance');     SQLEditSeance.Post;    SQLEditSeance.ApplyUpdates;   SQLTransaction2.Commit;... But I've got an error message on applyupdate that said : "operation cannot be performed on an inactive dataset". I can't understand why my dataset is ainactive, may be it's this code, may be it's an initialisation problem... I have to looking for this inactive reason... Thank you for your help ! ---------------------------------------------------------------------- Graeme · 2016-04-20 09:30 The joys of DataSet based programming and littering your forms with business rules and millions of events. I'm assuming by MVC you mean Model-View-Controller. Rather go for a clean separation between the various layers (storage, business rules, UI) of your application. Try tiOPF and Model-GUI- Mediator (very similar to MVC or MVP). The tiOPF framework takes care of the storage and business rule layers. It also hides the need to work with SQL and transactions directly. You can select which database components you want to use, which database servers (or text storage) to use and if you want Client/Server or 3-tier based applications - all controlled via simple compiler defines (no need to change your application code). You as a programmer only work with actual objects (eg: TPerson, TPersonList etc). The Model-GUI-Mediator (also included in the tiOPF repository) manages the UI and allows standard edit controls (eg: TEdit, TLabel) to become "object  aware" and with two- way synchronisation. You can even have multiple UI controls observing the same property of an object. Your forms units end up being very empty, yet fully functional. tiOPF:  http://www.tiopf.com tiOPF wiki page for FPC and Lazarus:   http://wiki.freepascal.org/tiOPF An article I wrote explaining Model-GUI-Mediator (MGM) - though the MGM implementation include with tiOPF is magnitudes more advance than what the article describes.   http://geldenhuys.co.uk/articles/ For further support or information on tiOPF, I welcome you to join the dedicated support newsgroup for further discussions. Details can be found here:  http://tiopf.sourceforge.net/Support.shtml ---------------------------------------------------------------------- gelinp · 2016-04-20 11:34 I know about TIOPF but my software is small and I wouldn't read a big book again... What I need is only the right schema to update into a dataset (master/detail). ---------------------------------------------------------------------- balazsszekely · 2016-04-20 11:52 QuoteBut I've got an error message on applyupdate that said : "operation cannot be performed on an inactive dataset". Did you use Commit before?  Because Commit will close the transaction. Switch to CommitRetaining instead. QuoteSQLTransactionX.CommitRetaining; ---------------------------------------------------------------------- Graeme · 2016-04-20 17:57 Quote from: gelinp on April 20, 2016, 01:34:24 pmI know about TIOPF but my software is small and I wouldn't read a big book again... tiOPF is equally suited for small and large applications. The tiOPFMapper tool makes it a breeze to get a working BOM and visitor classes written (fully compilable units) - it can literally be done in a minute or two. Also just because an application is small, doesn't mean you don't have to design it well. ;-) As for your usage of datasets and manual transaction handling and so forth, I unfortunately can't give any further advice. I haven't used that method of writing database applications in over 10 years. ---------------------------------------------------------------------- gelinp · 2016-04-21 05:30 I founded the reason of my error into Wiki pascal Tutorial 2 : Editing chapter. There the code below, explaining the reason was the transaction not started, so the error message 'inactive dataset' is not about the dataset itself ! 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.SaveChanges;// Saves edits done by user, if any.begin  try    if SQLTransaction1.Active then    // Only if we are within a started transaction;    // otherwise you get "Operation cannot be performed on an inactive dataset"    begin      SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...      SQLTransaction1.Commit; //... and commit them using the transaction.    //SQLTransaction1.Active now is false    end;  except  on E: EDatabaseError do    begin      MessageDlg('Error', 'A database error has occurred. Technical error message: ' +        E.Message, mtError, [mbOK], 0);      Edit1.Text := '';    end;  end;end; So, below is my code. I can't understand why the second assertion failed, telling me that Post inactive the transaction ! Why Post close the transaction before ApplyUpdates ? 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 TFormMain.EnregistrerClick(Sender: TObject);var  CurID : Integer;begin   if (DataModule1.SQLDetailSeances.Active and DataModule1.SQLTransaction2.Active) then  begin    CurID := SaveRecord(DataModule1.SQLDetailSeances, 'PKseance');    Assert(DataModule1.SQLTransaction2.Active); // TRUE, it's OK ...    DataModule1.SQLEditSeance.Post;    Assert(DataModule1.SQLTransaction2.Active); // FALSE ! Why Post close the transaction before ApplyUpdates ?     DataModule1.SQLEditSeance.ApplyUpdates;    DataModule1.SQLTransaction2.Commit;      DataModule1.SQLMasterSequences.Open;    DataModule1.SQLDetailSeances.Open;    DataModule1.SQLDetailSeances.Refresh;    LocateRecord(DataModule1.SQLDetailSeances, 'PKseance', CurID);     //DataModule1.SQLEditSeance.ParamByName('PKseance').AsInteger := DataModule1.SQLDetailSeances.FieldByName('PKseance').AsInteger;    DataModule1.SQLEditSeance.Open;    DataModule1.SQLEditSeance.Refresh;    PageControl1.Refresh;  end;end; About tiOPF I know it will be a good think for me to help design MVC with my application. But there is a problem with framework like this, it's the pveread to learn it, even if I write few code I have to read all the book. And also if there is a bug with my code, this bug could run into the framework and then it will be difficult to get the source of the error...