[SOLVED] Question about Data Module lazarus / 16-Databases ---------------------------------------------------------------------- 1HuntnMan · 2024-02-19 15:43 I'm relatively new to Lazarus.  On this app I started my first project, I started creating the main form and adding other forms which use a table(s), etc.  Got to reading about a Data Module so created one File-New-Data Module.  So, it appears to me that it's really just a form/unit. But, I am moving all the Data Tables and Data Sources over to it and every form that needs access to a table(s), just USING that form. It's working and I like that I have all the Data Table/Sources on just one form-Data Module. Is that it or does a Data Module form have different code, etc. than just another form/unit added to your app. that's var name is DMPMS vs. FrmClientsMgt? Also, on the Data Module I put all my table components on it, do I keep all the datasets there also or do I just put the DataSet component on the form that uses a table and point the dataset to the DMPMS.DbfPMS? ---------------------------------------------------------------------- Thaddy · 2024-02-19 16:20 TDataModule is about separation of responsabilities. They work as a container for data elements that can be distinctly handled as a group. That can be databases, tables, queries etc. And also the datasets. If your database application becomes more complex they will be become more important, but in principle they are not needed for simple solutions. They are simply a container, just like a Tframe. ---------------------------------------------------------------------- 1HuntnMan · 2024-02-19 18:27 Okay, finished moving all table and datasets to the data module.  Compiles with no errors. But, when I attempt to run application without Laz active I get an access violation. When I removed the TDbf components and the TDataSource components from all the forms except the DM, should I have left the DataSource components on the forms where the tables are referenced? So, for example if I have a DBGrid on a form, in it's DataSource property, I entered DataModulePMS.DSCategories. Would the correct way would have the DataSource on the form with the DBGrid and it's DataSource property pointing to the DataSource on the Categories form instead of the Data Module.  Would this be the issue? ---------------------------------------------------------------------- Hansvb · 2024-02-19 18:40 Take a look at the project source. Data module should usually be at the front of the uses list. ---------------------------------------------------------------------- Thaddy · 2024-02-19 19:20 No. In this particular case that does not matter. ---------------------------------------------------------------------- 1HuntnMan · 2024-02-19 21:10 I moved the DMESPMgt (unit name) to the beginning of the Uses clause and that cured the Access Violations! Tks Hansvb ---------------------------------------------------------------------- 1HuntnMan · 2024-02-19 21:20 Also, searching thru other posts, I found and learned how important the order of the units in the Uses clause. ---------------------------------------------------------------------- 1HuntnMan · 2024-02-20 15:23 I thought moving the Data Module to the beginning of the Uses clause in every form would eliminate having the tables Dbf's and DataSources on each form that allows editing of tables, i.e. States, Countries, Categories, etc. This is what I did so remove the clutter of every form having the Dbf/DS components on every form.  I removed them and moved them all to a Data Module. Corrected all the code on forms by adding the Data Module unit at the beginning (Thaddy's advice) USES on every form. The way this app is designed is the opening form is the Clients/Customers.  All tables are used on this form, Clients, Contacts, Categories, States, Countries, ReferredBy, etc. After moving to DataModule, the main form, Clients Mgt., no Access Violation errors (Abort or Continue risking data corruption). But, if the user decides to rebuild the tables under File-Maintenance, I can run data tables packing, regenerating indexes, etc. But, when I close, Access Violation and abort. If the user attempts to maintain the Client Categories, same problem when you close the Categories Maint. form, Access Violation and Abort, same with States, Countries, Referrals, etc. I have the Data Module at the beginning of every form's Uses clause. Also, when loading each form from the main, I'm ShowModal. 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 TFrmPMSMain.MnuFileMaintClick(Sender: TObject);begin  try    if PMSDM.DbfClients.Modified then      PMSDM.Dbf.ClientsPost;    PMSDM.DbfStates.Close;    PMSDM.DbfCntries.Close;    PMSDM.DbfCategories.Close;    PMSDM.DbfClients.Close;    Application.CreateForm(TFrmRebldPMSDB, FrmRebldPMSDB);    FrmRebldPMSDB.ShowModal;  finally    PMSDM.DbfClients.Open;    PMSDM.DbfStates.Open;    PMSDM.DbfCntries.Open;    PMSDM.DbfCategories.Open;    FrmPMSMain.Refresh;  end;end; Another bit of info. In the App's.lpr I also put the DM unit at the beginning of it's Uses clause because that's where the DataModule form is created just before the main form is created. 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 uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}  {$IFDEF HASAMIGA}  athreads,  {$ENDIF}  Interfaces, // this includes the LCL widgetset  Forms, datetimectrls, printer4lazarus, lhelpcontrolpkg,  { Main Unit added below ... }  DmPMS, ClientsMain; {$R *.res} begin  RequireDerivedFormResource:=True;  Application.Title:='PMS';  Application.Scaled:=True;  Application.Initialize;  Application.CreateForm(TPMSDM, PMSDm);  Application.CreateForm(TFrmClientsMain, FrmClientsMain);  Application.Run; ---------------------------------------------------------------------- Joanna · 2024-02-20 15:51 I had a problem with things trying to use data module before it was ready I believe I solved it by putting code into the unit initialization section to create the data module if it was nil. I was unable to control what order the units were initialized in. ---------------------------------------------------------------------- 1HuntnMan · 2024-02-20 18:03 Joanna,    I think at this point in my development of 2 systems that I'm going back to NO Data Module. On the other app I'm almost finished with, just testing by users I tried using a Data Module, 4 months ago and gave up. This new one I tried it again just for testing and maybe I would learn something new.  If you read earlier in this thread, THaddy advised, "Data module should usually be at the front of the uses list."  I did that and I could at least get into the Main Form without an access violation but, any forms launched from the Main Form has the same issue with constant "Access Violations".    I'm going to leave it at this and go back to my other app and wait a day.  If no real replies for solutions, then I'll come back to this current app and just remove the Data Module and move on with life. Tks and take care, 1HuntnMan aka Donald ---------------------------------------------------------------------- TRon · 2024-02-20 18:07 Quote from: 1HuntnMan on February 20, 2024, 04:23:54 pmCode: 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 TFrmPMSMain.MnuFileMaintClick(Sender: TObject);begin  try    if PMSDM.DbfClients.Modified then      PMSDM.Dbf.ClientsPost;    PMSDM.DbfStates.Close;    PMSDM.DbfCntries.Close;    PMSDM.DbfCategories.Close;    PMSDM.DbfClients.Close;    Application.CreateForm(TFrmRebldPMSDB, FrmRebldPMSDB);    FrmRebldPMSDB.ShowModal;  finally    PMSDM.DbfClients.Open;    PMSDM.DbfStates.Open;    PMSDM.DbfCntries.Open;    PMSDM.DbfCategories.Open;    FrmPMSMain.Refresh;  end;end;  Just some verification question... if you create FrmRebldPMSDB for use with showmodal each time you select the menu item... then where exactly is it destroyed ? ---------------------------------------------------------------------- Hansvb · 2024-02-20 20:40 As far as I know, the data module has to be created first and then the form(s). You can do that in the project source. That's somerhing different then putting the data module in each unit at the front. If that doesn't solve the access violation, then with me it's usually the case that I want to use a data source that has already been shut down. See the last post in: https://forum.lazarus.freepascal.org/index.php?topic=41408.0 ---------------------------------------------------------------------- dseligo · 2024-02-21 00:22 Quote from: Hansvb on February 20, 2024, 09:40:50 pmAs far as I know, the data module has to be created first and then the form(s). It has to be created before you use it. You can also change creation order in menu Project/Project Options/Forms in the 'Auto-create forms' list. See attachment: DM is name of my data module (I have other data modules in this project, but I create them manually). ---------------------------------------------------------------------- TRon · 2024-02-21 00:41 Quote from: dseligo on February 21, 2024, 01:22:05 amIt has to be created before you use it. +1 It also means that when you depend on the datamodule to be created first that you seem to do all kind of initializations before a (single) form is even been shown (which is usually a bad idea). ---------------------------------------------------------------------- egsuh · 2024-02-21 03:38 The orders of units appearing in "uses" clause do not matter IN GENERAL. They may matter when dependencies exist among the units in the uses clause. Based on your explanations, it seems that trying to access datamodules/forms which have not been created causes access violations. You may auto-create datamodules/forms or create within the codes. So the creation order seems to matter more in this case. ---------------------------------------------------------------------- 440bx · 2024-02-21 03:42 Quote from: egsuh on February 21, 2024, 04:38:23 amThey may matter when dependencies exist among the units in the uses clause. They also matter when multiple units interface functions or procedures with the same name.  Depending on the order, the wrong function or procedure may end up being called. ---------------------------------------------------------------------- egsuh · 2024-02-21 03:53 QuoteThey also matter when multiple units interface functions or procedures with the same name.  Depending on the order, the wrong function or procedure may end up being called. Yes, it's true. I think we should try to avoid those designs. ---------------------------------------------------------------------- 1HuntnMan · 2024-02-22 19:00 Okay, earlier this morning, I have a Data Module that works.  Thanks all for all the great comments and advice.  The big thing that I learned is the Data Module HAS TO be created in your app.lpr BEFORE you create your main form.  Also, putting the Data Module as your first USE unit in your data forms.  Also, I discovered that ShowModal was a bit of an issue for Data forms.  Non-Data forms, i.e. an About (your app.) form I use ShowModal. I just changed the data forms to just form.show. ...Take Care ---------------------------------------------------------------------- TRon · 2024-02-22 19:12 Quote from: 1HuntnMan on February 22, 2024, 08:00:16 pmThe big thing that I learned is the Data Module HAS TO be created in your app.lpr BEFORE you create your main form. In that case, sorry to say, you learned wrong. QuoteAlso, putting the Data Module as your first USE unit in your data forms. Same answer as above. QuoteAlso, I discovered that ShowModal was a bit of an issue for Data forms.  Non-Data forms, i.e. an About (your app.) form I use ShowModal. I just changed the data forms to just form.show. ...Take Care That indicates that the flow your program depends on how you have set your (database) properties at design time. All the conclusions you have made so far depend solely on that, and nothing else. /that/ is the thing you should have learned  And I am sorry to have to say it the way I just did above but I failed to see how that message could be softened other than to say: yes you are right in your specific situation because you choose to use that (program) flow. ---------------------------------------------------------------------- egsuh · 2024-02-23 05:32 You'll learn, but to explain a bit more: QuoteThe big thing that I learned is the Data Module HAS TO be created in your app.lpr BEFORE you create your main form.  If your forms do not access anything in data module at the creation of forms, data module doesn't have to be created before forms. In your case, I think datasets (TSQLQuery, TBufDataSet, etc.)  are on data module, TDataSource and data controls  (TDBGrid, TDBEdit, etc.) are on forms, and your datasource's  dataset is pointing to datasets on the data module (hard coded). In this case, at the creation  of forms, it tries to access data module, and data module should have been created before the creation of forms. But if you assign datasource's dataset property at runtime, you may created data module within the forms.  For example, 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.FormCreate(Sender: TObject);begin    DM1 := TDM1.Create (nil);   DataSource1.DataSet := DM1.SQLQuery1;     DM1.SQLQuery1.Open; end; QuoteAlso, putting the Data Module as your first USE unit in your data forms.  Generally this is not important. QuoteShowModal was a bit of an issue for Data forms.  Non-Data forms, i.e. an About (your app.) form I use ShowModal. I just changed the data forms to just form.show. With ShowModal, the modal form is not destroyed at close until you free it explicitly. I made following example: 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   with Tform2.create (nil) do begin      ShowModal;      if ModalResult = mrOK   // this form is closed at this point            then showmessage(Edit1.Caption); // Edit1 is on TForm2, because of "with"      Free;   // and form is freed here.       //  if edit1.caption = ..    // this will cause invalid access, because the form has been freed.    end;end;  I attached the sample project. Here, you have to notice: 1) In project options, form1 is auto-created while form2 is just available. 2) On TForm2, btn1.ModalResult = mrOK, and btn2.ModalResult = mrCancel (at object inspector). ---------------------------------------------------------------------- Joanna · 2024-02-23 23:22 It’s good that he got it to work regardless. He can always improve later. When I was having problems with trying to use datamodule code before it was created I also tried creating the data module before the other forms but it didn’t help. Apparently the units are initialized before any form is created including the data module?