Jump to content

TDataModule - To use or NOT to use


vbdavie

Recommended Posts

I've read as many posts as I could find and it seems that all the comments indicate to use the uniGUI version of the datamodule AND NOT the TDataModule that comes with standard Delphi apps.

 

I have a delphi desktop app that does a LOT (hundreds of data manipulation functions) of DB functions on my DB.

 

We need to create a Web version of the app and I thought that if I could "Re-Use" my datamodule, that would save so so so much time. It appears that in uniGUI EXE mode, I have NO ISSUES at all. I was estatic<happy>, and so I tested it in the DLL(ASAPI) mode and it just locks up or doesn't work at all.

 

I tried creating the datamodule a few different ways:

    1.  Application.CreateForm(TFDataModule,FDataModule);

    2.  FDataModule:=TFDataModule.Create(Nil);
Boths of these do not work in the DLL mode. What is it about the TDataModule that makes it not work ONLY IN DLL mode? It works in my Desktop app and in the UniGUI EXE mode.

 

YET another difference between EXE and DLL mode :(

 

Is there a good solution so that I can RE-USE my code between my desktop app and my uniGUI DLL?

 

Thanks very much

Davie

P.S. What is the RTL property on forms?

 

Link to comment
Share on other sites

Hi Davie,

 

When I converted a Delphi app to web, using Unigui, I just moved all

my data access components from the TDatamodule to the unigui

Datamodule. Copy and paste...same with the code.

Why do you need to re-use the Delphi version of the TDatamodule ?

 

Kaj

Link to comment
Share on other sites

Because I am NOT converting and getting RID of old app. I am creating a web "companion" that will utilize MANY of the functions that I have already created. The forms of course will all have to be re-created, but I wanted to keep as much core code as possible.

 

Davie

Link to comment
Share on other sites

OK, so you want to use one datamodule unit within two different projects,

basically...without altering anything...can't you use some compiler directives

to just alter the classname of the datamodule, depending on which project is compiled?

Link to comment
Share on other sites

Actually, I was able to get the TDataModule to work properly. The problem was that I had kept the created object in a "GLOBAL" variable... which is BAD of course. BUT I have a ton of old working code that depends on that global object ;(  SOOOooo, I decided to create a function that goes by the SAME NAME as the global name: For example: My global variable was...

 

Var

    FDataModule:TDataModule;

 

I replaced it with this.....

 

Function FDataModule:TDataModule;

 

And this function figures out what the correct pointer is :)  Basically, I have a string list, and for every SESSIONID, I have the object of the stringlist pointing to the newly created TFDataModule object. That meant I had to create a "CreateFDataModule" function and a "FreeFDataModule" procedure that both utilize my SessionList string list of objects. That way depending on which session is trying to do database work, it will of course call my "FDataModule" function<which use to be a pointer> So, now my code utilizes the PROPER object <in respect to the sessionID> and I keep track of as many objects as I have sessions. It was easier to create my 3 little functions (about 60 EZ lines of code) and to modify my creation and freeing code (about 4 references) THAN to change literally hundreds of places where the static object pointer was being referenced :)

 

So, now it works perfectly :)

 

Davie

P.S. Here's my 3 little functions in case you care.

 

Var
  P_GetSessionID:TFunctionString;          // points to function that gives me string representing the unique SessionID
  SessionList:TStringList;                          // needs to be initialized as a SORTED list
  Function FDataModule:TFDataModule;  // Used to be a VARIABLE
Var
  FDataModule_Instance:TFDataModule;     //Use this if not in web mode - faster
  Function CreateFDataModule:TFDataModule;  
  Procedure FreeFDataModule;
 

Implementation

 

Function FDataModule:TFDataModule;
Var
  SessionID:String;
  Index:Integer;
  DataIndex:Integer;
Begin
If G_WebMode Then
   Begin
   If Assigned(P_GetSessionID)=False Then
      Raise Exception.Create('Function FDataModule: P_GetSessionID is NOT initialized.');
   SessionID:=P_GetSessionID;
   If SessionList.Find(SessionID,Index) Then
      Begin
      Result:=TFDataModule(SessionList.Objects[index]);
      End
   Else
      Result:=Nil;
   End
Else
   Result:=FDataModule_Instance;
End;
Function CreateFDataModule:TFDataModule;
Begin
If G_WebMode Then
   Begin
   If Assigned(P_GetSessionID)=False Then
      Raise Exception.Create('Function FDataModule: P_GetSessionID is NOT initialized.');
   Result:=TFDataModule.Create(Nil);
   SessionList.AddObject(P_GetSessionID,Result);
   End
Else
   Begin
   Application.CreateForm(TFDataModule,Result);
   FDataModule_Instance:=Result;
   End;
End;
Procedure FreeFDataModule;
Var
  vObject:TFDataModule;
  SessionID:String;
  Index,DataIndex:Integer;
Begin
If G_WebMode Then
   Begin
   If Assigned(P_GetSessionID)=False Then
      Raise Exception.Create('Function FDataModule: P_GetSessionID is NOT initialized.');
   SessionID:=P_GetSessionID;
   If SessionList.Find(SessionID,Index) Then
      Begin
      vObject:=TFDataModule(SessionList.Objects[index]);
      vObject.Free;
      SessionList.Delete(Index);
      End;
   End
Else
   Begin
   FDataModule_Instance.Free;
   FDataModule_Instance:=Nil;
   End;
End;
 

Link to comment
Share on other sites

This is not thread safe !!!. (session list ist a global var and there is no access control, ... )

 

Better you store a reference to your DataModule in a Field of TUniMainModule. That would be easy to read/write - no thoughts about sessions and threads, because thread safe and per session by default.

 

 

 

Link to comment
Share on other sites

I had already thought about adding an EnterCriticalSection or some such thing, but you make a good point, under normal circumstances.

 

My circumstance however, is that I have a ton of old code that refers to a global variable named FDataModule, and so that's why I chose the way I did. Many of these modules may or may not be linked into the Web version and may or may not be linked into the desktop version.

 

Thoughts?

 

Davie

Link to comment
Share on other sites

Additional you can use a (your) function "FDataModule" in your DataModule as follows:

 

function FDataModule: TFDataModule;

begin

  result := uniMainModule.FDataModule;

end;

 

Instead of "uniMainModule.FDataModule" you could you use a (String)List/Array/HashMap/... as UniMainModule field with containing all datamodules for the current session; so you have not to declare something for each of your modules in UniMainModule.

Link to comment
Share on other sites

We have large VCL desktop application, when we started to add portal service for the customer, we use same source for both platforms (Desktop & web)

 

for the DataModule I use it as following:

 

on TUniGUIMainModule:

type
  TMM = class(TUniGUIMainModule)
    ...
  public
   DM: TDM;
  end;

.....

//------------------------------------------------------------------------------
procedure TMM.UniGUIMainModuleCreate(Sender: TObject);
begin
 DM  := TDM.Create(UniApplication);

That's make it accessible and thread safe with UniGUi.

var
  qry :TMyQuery ;
begin
    qry := TMyQuery.Create(nil);
  try
    qry.Connection := {$IFDEF WebApp}MM.DM{$ELSE}DM{$ENDIF}.ConEMS;

and you can change the code that shared between VCL & Uni to :

 

 

 

 

P.S. What is the RTL property on forms?

 

It's Related to set the aligment of form and controls on it to be from Right To Left to support RTL Languages such as Arabic and Farsi.

 

 

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...