Jump to content
PenelopeSkye

Move objects to a second Data Module

Recommended Posts

I have a Data Module where it is impossible to find objects, see attached screenshot. I inherited it in this state.

 

I just have to scroll through the objects in the structure pane to find anything.

 

I would like to create a second Data Module file and move some of the database objects that I work with most frequently.

 

Does anyone have any instructions to do this?  I would love to start cutting and pasting but I am quite sure it can't be that simple!

 

Thanks!

DataModule.png

Share this post


Link to post

WOW!  That's very crazy man! :classic_cheerleader::classic_cheerleader:

in Text mode, you can find and copy/paste in second "place" (DM)... of course, very tiring, but given this tangle of objects, nothing will be very easy and reliable in an automation without any human intervention.

because after copy your obj, of couse, needs pay attention on events code... in DFM mode, copy it too!

🤣

Edited by programmerdelphi2k

Share this post


Link to post

Actually you CAN just copy/cut and paste the controls to another datamodule, but any event handlers and some links can get lost.

 

I suggest to copy the event handlers in the pas file first and then copy the controls in the designer. That way they are re-wired in the target module.

Also make sure that you always copy all related components like a datasource linked to a query or vice versa in master-detail relations.

 

Whatever you do, make sure you can re-establish the original state if anything went wrong.

Share this post


Link to post

I would try another way. To gradually create individual objects dynamically if necessary.
One of the possibilities is to find out where a specific object is used everywhere. Then decide accordingly.
If it is used only in one place, then there is nothing to think about. But it is a very laborious procedure.

It is estimated that there are around 500 objects:classic_ohmy: It is not normal!

  • Like 2

Share this post


Link to post

Thank you everyone!  I am going to just start moving one object at a time as I work with them, find out where it is used and act accordingly.

Share this post


Link to post

You could try something along these lines:

  1. you create a new "DataModule in your project" (thus, Delphi already creates the .PAS unit and the .DFM file! = more easy way!
  2. Now, you can use a procedure like the one below to read the components you want to remove from the source-datamodule and insert them into your new datamodule created above!

Remembering that "InsertComponent()" will automatically try to remove the component from the source to insert it in the target!

 

type
  TMyArrayOfThisComponents = TArray<string>;

procedure MyInsertAllComponentsOnDM(const ADMsource, ADMtarget: TDataModule);
begin
  while (ADMsource.ComponentCount > 0) do
    ADMtarget.InsertComponent(ADMsource.Components[0]); // "remove" from source and "insert" on target!
end;

procedure MyInsertThisComponentsOnDM(const ADMsource, ADMtarget: TDataModule; const AComponents: TMyArrayOfThisComponents);
begin
  for var C in AComponents do // all list of components names...
    begin
      for var i: integer := 0 to (ADMsource.ComponentCount - 1) do
        if (ADMsource.Components[i].Name = C) then // if exists on DMsource...
          begin
            ADMtarget.InsertComponent(ADMsource.Components[i]); // "remove" from source and "insert" on target
            //
            break; // next components-name...
          end;
    end;
end;

procedure TForm1.BtnUsingDMonProjectClick(Sender: TObject);
begin
  try
    // DataModule3/Unit3 is a DataModule created on this project, for example!
    //
    // MyInsertAllComponentsOnDM(DataModule2, DataModule3);
    MyInsertThisComponentsOnDM(DataModule2, DataModule3, ['FDQuery1', 'FDConnection', 'dsQuery1', '...']);
    //
    WriteComponentResFile('Unit3.dfm', DataModule3); // Unit3.pas and Unit3.DFM "already" exists in your project!!!
  except
    // ???
  end;
end;

procedure TForm1.BtnCreatingAnewDMfileClick(Sender: TObject);
var
  MyNewDM: TDataModule;
begin
  MyNewDM := TDataModule.Create(nil);
  try
    MyNewDM.Name := 'MyNewDM';
    try
      // MyInsertAllComponentsOnDM(DataModule2, MyNewDM);
      MyInsertThisComponentsOnDM(DataModule2, MyNewDM, ['FDQuery1', 'FDConnection', 'dsQuery1', '...']);
      //
      WriteComponentResFile('MyNewDM.dfm', MyNewDM);
      //
      // now, you needs create your "UNIT.pas" for this "MyNewDM.DFM file" like IDE do it!
    except
      // ???
    end;
  finally
    MyNewDM.Free;
  end;
end;

now, you'll have your components inserted in your "new datamodule", then, you can just "ADD it" in your project, and create your "event" (or copy it from old datamodule)

  • in the tests, the properties are kept as in the source!

you would can automatizate this, but needs much more code to verify each object and your events, ...read source, write target ...

Edited by programmerdelphi2k
  • Haha 1

Share this post


Link to post

1. Crerate a list of the components on thedataset

2. Clone the datamodul with a filemanagaer (copy pas and dfm, rename unit name and datamodul class in the pas and at the top of the dfm) 

3. now pick a group from the list and keep only them on the 2nd datamodul, delete the others

4. start refactoring the project

5. goto 2.

  • Sad 1

Share this post


Link to post

+1 for @Stano's idea. At a large number like this it's better to write a factory code and request these items runtime.

  • Like 1

Share this post


Link to post
19 minutes ago, aehimself said:

+1 for @Stano's idea. At a large number like this it's better to write a factory code and request these items runtime.

Good luck with that on a giant legacy project where the DAC's with its fields and co. are living at the visual level an they are also used to it.

Share this post


Link to post

We are developing a 20 year old application at work: over 1,5M LOC, 500-700 frames, couple thousands of units. Today we had a meeting with our teamlead where we successfully convinced him to allow the framework team to go for a full visual and codebase refactoring - effectively building it from the ground up once more; reusing mostly experience and tiny chunks of the original code (yeah, it's that bad).

 

There are things what you can not delay any further. If this is what is needed to improve the coding experience devs will have to get used to the new model. It's for their own sake aswell, after all.

 

With all that said, I'm fully aware that OP probably won't go in this direction. I'm leaving my remark here for future visitors, who might still be able to change their design seeing what the easy way can / will cause.

  • Like 2

Share this post


Link to post
1 hour ago, aehimself said:

go for a full visual and codebase refactoring - effectively building it from the ground up once more

image.png.c5a1d3243b35da8b9bd9fc5dd9c088d5.png

  • Haha 1

Share this post


Link to post

In fact, Delphi teaches us bad things with all this visual & RAD button-dropping. It's good for small apps but when they grow, old habits remain and lead to these nightmare. I was in the same situation with an app started when I started learning Delphi so it's evolving with me. In that app I significantly reduced the number of objects in datamodules by changind all temporary queries (that is, those which do not have any datasource attached) from design-time components to temporary objects created at run-time. Their SQLs are defined as literals in datamodule unit and field list is generated dynamically. And with interface-based wrapper the code is pretty simple

with GetTempQuery(Database).Q do
begin
  SQL.Text := SQL_Insert;
  Params ...
  ExecSQL;
end;

 

Edited by Fr0sT.Brutal
  • Like 3

Share this post


Link to post

As I read each successive text I would think - I'll try that!  Then the next Idea was also good!

 

I'm going to try Programmers code. I am not the most experienced Pascal developer so I may not be able to make it work.

 

If I can't I will clone the current data module but also see if I can easily create the objects at run-time.

 

If I can ever build it from the ground up it will be in C#!!!!

 

Thanks again everyone!

Share this post


Link to post

1. Open the project.

2. Open the TDataModule source file.

3. Change the Name property of the TDataModule to a new unique name.

3. Click File > Save As... and save it with a new file name.

4. Add the original TDataModule back to the project.

 

In the new TDataModule you can start deleting components and event handlers.

 

1. Select the component you  want to delete.

2. In the Object inspector, click the Events tab.

3. For any events that have been created for the component, double-click the event handler name.

4. Delete the code within the event handler BUT DO NOT delete the event handler.

 

procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  // delete the code in here but
  // leave everything between procedure and end;
end;

 

5. Click File > Save and the handler will be removed.

Edited by weirdo12

Share this post


Link to post

Don't forget to check if deleted component is referred by other components! On delete these refs just get emptied silently. Form view as text will help on this. Anyway form text view helps much because you can see all non-default properties of a component including event handlers. Then do text search by component name to find all refs

Edited by Fr0sT.Brutal

Share this post


Link to post
On 2/9/2023 at 12:54 AM, Anders Melander said:

image.png.c5a1d3243b35da8b9bd9fc5dd9c088d5.png

or Retire.  Sometimes, there is new software out there that can do the job.

Share this post


Link to post

I never liked the visual data module.  I'd prefer it to have a listview of components rather than a collection of icons.

 

On event handlers.  Assign them in code.  They break so easily otherwise.

Share this post


Link to post
1 hour ago, Lars Fosdal said:

I never liked the visual data module.

It's the RAD from RAD Studio.

I remember at the CeBIT 99 or 2000, Borland presentation, ~click click ctrlA click click drag&drop and the form was filled with the dbcontrols.

Share this post


Link to post

I am definitely not fond of the data module. 

 

And I am also concerned about all the various places these objects are referred to.  It has been a learning process!

Share this post


Link to post

on code it's more easy find it... just rename your "data module unit" and try re-compile it... you'll see many errors on compiling...

 

on components you need open each "form/datamodule" to see what component (ex. Datasets) use it! or open the form/datamodule as TEXT and find the name

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×