I'm building an application that contains around 30 Forms. I need to manage sessions, so I would like to have a global LoggedInUser variable accessible from all forms. I read "David Heffernan"'s post about global variables, and how to avoid them but I thought it would be easier to have a global User variable rather than 30 forms having their own User variable.
So I have a unit: GlobalVars
unit GlobalVars;
interface
uses User; // I defined my TUser class in a unit called User
var
LoggedInUser: TUser;
implementation
initialization
LoggedInUser:= TUser.Create;
finalization
LoggedInUser.Free;
end.
Then in my LoginForm's LoginBtnClick procedure I do :
unit FormLogin;
interface
uses
[...],User;
type
TForm1 = class(TForm)
[...]
procedure LoginBtnClick(Sender: TObject);
private
{ Déclarations privées }
public
end;
var
Form1: TForm1;
AureliusConnection : IDBConnection;
implementation
{$R *.fmx}
uses [...]GlobalVars;
procedure TForm1.LoginBtnClick(Sender: TObject);
var
Manager : TObjectManager;
MyCriteria: TCriteria<TUser>;
u : TUser;
begin
Manager := TObjectManageR.Create(AureliusConnection);
MyCriteria :=Manager.Find<TUtilisateur>
.Add(TExpression.Eq('login',LoginEdit.Text))
.Add(TExpression.Eq('password',PasswordEdit.Text));
u := MyCriteria.UniqueResult;
if u = nil then
MessageDlg('Login ou mot de passe incorrect',TMsgDlgType.mtError,[TMsgDlgBtn.mbOK],0)
else begin
LoggedInUser:=u; //Here I assign my local User data to my global User variable
Form1.Destroy;
A00Form.visible:=true;
end;
Manager.Free;
end;
Then in another form I would like to access this LoggedInUser object in the Menu1BtnClick procedure :
Unit C01_Deviations;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
FMX.ListView.Types, FMX.ListView, FMX.Objects, FMX.Layouts, FMX.Edit, FMX.Ani;
type
TC01Form = class(TForm)
[...]
Menu1Btn: TButton;
[...]
procedure Menu1BtnClick(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;
var
C01Form: TC01Form;
implementation
uses [...]User,GlobalVars;
{$R *.fmx}
procedure TC01Form.Menu1BtnClick(Sender: TObject);
var
Assoc : TUtilisateur_FonctionManagement;
ValidationOK : Boolean;
util : TUser;
begin
ValidationOK := False;
util := GlobalVars.LoggedInUser; // Here i created a local user variable for debug purposes as I thought it would permit me to see the user data. But i get "Inaccessible Value" as its value
util.Nom:='test';
for Assoc in util.FonctionManagement do // Here is were my initial " access violation" error occurs
begin
if Assoc.FonctionManagement.Libelle = 'Reponsable équipe HACCP' then
begin
ValidationOK := True;
break;
end;
end;
[...]
end;
When I debug I see "Inaccessible Value" in the value column of my user. Do you have any idea why ?
I tried to put an integer in this GlobalVar unit, and i was able to set its value from my login form and read it from my other form..
I guess I could store the user's id, which is an integer, and then retrieve the user from the database using its id. But it seems really unefficient.
GlobalVarto the uses clause. We cannot tell what that is. Maybe it really isGlobalVars. Or maybe you have another unit namedGlobalVar. A big part of your problem is the imprecision evident in the question. If you taught yourself how to be precise and accurate then you'd likely be able to debug the code yourself. Please add SSCCE.LoggedInUsermore than once. And then ask yourself why you use global variables.TUserargument and provide aLoggedInUserproperty to all forms.