Avatar billede retep Nybegynder
01. marts 2001 - 12:00 Der er 11 kommentarer og
2 løsninger

Databasekomponent i unit for sig?

Hejsa :)

Jeg har flere skærmbilleder og units der skal tilgå en database. Derfor vil jeg gerne lave én unit der sørger for databasekomponenten (TIBDatabase). Jeg har oprettet en ny unit, men hvordan benytter jeg de komponenter fra komponentmenúen når der ikke er en tilhørende form jeg kan \'trække\' dem ned på?

Skal jeg selv til at kreere objekterne eller er der en eller anden smart metode?

Mvh
Retep
Avatar billede martinlind Nybegynder
01. marts 2001 - 12:04 #1
Brug det dertil indrettede TDatamodule
Avatar billede pellelil Nybegynder
01. marts 2001 - 12:13 #2
Brug (som også martinlind forslår) et Data-module. Jeg har således lavet et gennerelt DataModul som jeg bruger i alle mine projekter. Dette tager sig af at logge på vores InterBase server (og AS/400). Ydermere giver det dig den fordel (i forhold til at placere en TIBDatabase på hver form) at der kun laves en forbindelse til serveren og der bruges kun tid på at åbne/lukkke denne når programmet startes/stoppes (ved at bruge TDataModule\'ts OnCreate/OnDestroy.

Ligeledes kan du i dette datamodul placere DB-relaterede funktioner som går på tværs af dine projekter: Bruger-logon, Låsning af records osv.
Avatar billede retep Nybegynder
01. marts 2001 - 12:52 #3
pellelil>> Lyder spændende ;))) Er den noget du kan undvære en kopi af?? Vil meget gerne se det. Eller endnu bedre hvis du har et mindre projekt hvor jeg kan se hvorledes du opbygger det hele. Er første projekt jeg laver der skal køre mod en database, og er lidt i tvivl om hvordan jeg skal strukturere det smart...

Hvis du vil, er min mailadresse peter@aude.dk
Og der kompenseres selvfølgelig med flere points ;)

Mvh
Retep


Avatar billede pellelil Nybegynder
01. marts 2001 - 13:16 #4
Jeg har desværre et et \"mindre projekt\" der egner sig så (i første omgang) må du nøjes med nedenstående.

Lav et nyt projekt. Dernæst vælger du File->\"New->New->Data Module\" (ikke at forveksle med \"File->New->Data Modules->Customer Data\". I dette DataModule indsætter du en TIBDatabase og en TIBTransaction (som du \"kobler sammen\"). Jeg holder mine Database-connection (og transaktion) lukket indtil programmet starter hvorefter jeg lader Data Modulets \"OnCreate\" åbne denne. Ligeledes når programmet afsluttes så sikre jeg mig at der ikke er nogle aktive transaktioner og jeg sørger for at database connection\'en igen lukkes (i DataModulet \"OnDestroy\"). Dette kunne se ud som flg:

<SNIP>
procedure TDataModuleFccInterBase.DataModuleCreate(Sender: TObject);
begin
  FormWait := TFormWait.Create(Nil);
  FormWait.Show;
  FormWait.ProgressBar1.Position := 0;
  FormWait.ProgressBar1.Max      := 2;
  FormWait.Update;
  //--- Logon to InterBase server ---
  if IB_FCCInterBase <> nil then begin
    if IB_FCCInterBase.Connected then IB_FCCInterBase.Connected := False;
    with IB_FCCInterBase do begin
      Params.Values[\'user_name\'] := \'IBUSERNAME\';
      Params.Values[\'password\']  := \'IBPASSWORD\';
      LoginPrompt := False;
      Connected  := True;
    end;
  end;
  if IBT_FCCInterBase <> nil then begin
    if IBT_FCCInterBase.Active = False then IBT_FCCInterBase.Active := True;
  end;
  FormWait.ProgressBar1.Position := FormWait.ProgressBar1.Position + 1;
  FormWait.ProgressBar1.Update;
  //--- Logon to AS/400 ---
  if DB_EGDTA <> nil then begin
    if DB_EGDTA.Connected then DB_EGDTA.Connected := False;
    with DB_EGDTA do begin
      Params.Values[\'USER NAME\'] := \'AS400USERNAME\';
      Params.Values[\'PASSWORD\']  := \'AS400PASSWORD\';
      LoginPrompt := False;
      Connected  := True;
    end;
  end;
  FormWait.ProgressBar1.Position := FormWait.ProgressBar1.Position + 1;
  FormWait.ProgressBar1.Update;
  FormWait.Close;
end;

procedure TDataModuleFccInterBase.DataModuleDestroy(Sender: TObject);
begin
  //--- LogOff InterBase server ---
  if (IBT_FCCInterBase <> Nil) and (IBT_FCCInterBase.InTransaction) then IBT_FCCInterBase.Commit;
  if (IB_FCCInterBase <> Nil)  and (IB_FCCInterBase.Connected)      then IB_FCCInterBase.Connected := False;
  //--- LogOff AS/400 ---
  if (DB_EGDTA <> Nil)        and (DB_EGDTA.Connected)            then DB_EGDTA.Connected := False;
end;
</SNIP>

Ovenstående logger dels på og af vores InterBase og AS/400. Desuden har jeg en FormWait som fortæller brugeren at de skal \"klappe hesten\" indtil der er logget på både InterBase og AS/400. Denne FormWait indeholder også en ProgressBar, som opdateres.

I de forms hvor du har brug for at access dine database, kan du bare include dit DataModule. Når du på disse forms indsætter TIBDataSet (og lign.) så sætter du bare disse\'s \"DataBase\" til at pege på den TIBDataBase der er på dit DataModule (i mit tilfælde: \"DataModuleFccInterBase.IB_FCCInterBase\").

Ligeledes hvis du eksempelvis har nogle TIBDataSets du ofte anvender så kan du placere disse på dit DataModule også da du således kan anvende disse. Jeg har eksempelvis på mit DataModule en TIBDataSet (med tilhørende TIBTransaction) som jeg anvender sammen med min bruger-logon funktion (jeg har således på IB lavet min egen brugerdatabase - da programmerne logger på vha. et \"standard IB brugernavn/password\"

<SNIP>
Function _LogOnUser(UserIdStr, DecryptedPassword: String; Silent:Boolean): Boolean;
begin
  Result := False;
  UserIdStr := AnsiUpperCase(UserIdStr);
  if (UserIdStr = \'\') then begin
    if not(Silent) then MessageDlg(\'You haven\'\'t entered a username\', mtError, [mbOK], 0);
    Exit;
  end;
  with DataModuleFccInterBase do begin
    if not trUserLogon.InTransaction then trUserLogon.StartTransaction;
    dsetUserLogon.Params.ByName(\'USERID_APP\').AsString := UserIdStr;
    if not dsetUserLogon.Active then dsetUserLogon.Open;
    try
      dsetUserLogon.First;
      if not dsetUserLogon.EOF then begin
        dsetUserLogon.Edit;
        if dsetUserLogon.FieldByName(\'ACCOUNT_DISABLED\').AsInteger = 1 then begin
          dsetUserLogon.FieldByName(\'FAILED_LOGON\').AsInteger := dsetUserLogon.FieldByName(\'FAILED_LOGON\').AsInteger + 1;
          if not(Silent) then MessageDlg(\'Your user-profile is currently disabled. You need to contact the \'+#13+#10+
            \'administrator in order to have your user-profile enabled again.\', mtError, [mbOK], 0);
        end else begin
          if _DecryptPassword(dsetUserLogon.FieldByName(\'PWD\').AsString) = DecryptedPassword then begin
            dsetUserLogon.FieldByName(\'LAST_LOGON\').AsDateTime  := Now;
            dsetUserLogon.FieldByName(\'FAILED_LOGON\').AsInteger := 0;
            with _GlobalUserLogedOn do begin
              UserIdStr  := dsetUserLogon.FieldByName(\'USERID_APP\').AsString;
              UserIdInt  := dsetUserLogon.FieldByName(\'USERID_DB\').AsInteger;
              FName      := dsetUserLogon.FieldByName(\'NAME\').AsString;
              FPwd        := dsetUserLogon.FieldByName(\'PWD\').AsString;
              FPwdExpired := (dsetUserLogon.FieldByName(\'PWD_EXPIRED\').AsInteger = 1);
              FPwdDate    := dsetUserLogon.FieldByName(\'PWD_DATE\').AsDateTime;
              FUserLevel  := dsetUserLogon.FieldByName(\'USERLEVEL\').AsInteger;
              FNetworkID  := dsetUserLogon.FieldByName(\'NETWORKID\').AsString;
              FAS400ID    := dsetUserLogon.FieldByName(\'AS400ID\').AsString;
              FEMail      := dsetUserLogon.FieldByName(\'EMAIL\').AsString;
              FMailAlias  := dsetUserLogon.FieldByName(\'MAILALIAS\').AsString;
            end;
            Result := True;
          end else begin
            dsetUserLogon.FieldByName(\'FAILED_LOGON\').AsInteger := dsetUserLogon.FieldByName(\'FAILED_LOGON\').AsInteger + 1;
            if dsetUserLogon.FieldByName(\'FAILED_LOGON\').AsInteger >= _MaxFailedLogon then begin
              dsetUserLogon.FieldByName(\'ACCOUNT_DISABLED\').AsInteger := 1;
              if not(Silent) then MessageDlg(\'You have entered a wrong password too many times, \'+#13+#10+
                \'so your user-profile has been disabled. \'+#13+#10+\'\'+#13+#10+
                \'You need to contact the administrator in order to have\'+#13+#10+
                \'you user-profile enabled again.\', mtError, [mbOK], 0);
            end else begin
              if not(Silent) then MessageDlg(\'You have entered a wrong username/password.\', mtError, [mbOK], 0);
            end;
          end;
        end;
        dsetUserLogon.Post;
      end else begin
        if not(Silent) then MessageDlg(\'You have entered a wrong username/password.\', mtError, [mbOK], 0);
      end;
    finally
      if trUserLogon.InTransaction then trUserLogon.Commit;
      if dsetUserLogon.Active then dsetUserLogon.Close;
    end;
  end;
end;
</SNIP>
Avatar billede retep Nybegynder
01. marts 2001 - 13:24 #5
Tusind tak ;))

Lige et lille bispørgsmål. Bruger man kun én transaktions-ting til et helt projekt? Eller opretter man nye undervejs?

Håber det er points nok...
Avatar billede retep Nybegynder
01. marts 2001 - 14:44 #6
Med nye transaktioner undervejs mener jeg, laver man en ny TIBtransaction til hver query, eller bruger man den ene Transaction man oprettede i starten til alle querys og datasets?

Håber ikke jeg spørger for dumt, men er først liiige ved at finde ud af det her ;)

Mvh
Retep
Avatar billede retep Nybegynder
01. marts 2001 - 14:46 #7
Hov, nu er jeg vist lidt for hurtig til at spørge i stedet for selv at undersøge!

Fra Delphi hjælpen:
Note:    In MIDAS applications, every query must be in its own transaction.  You must use one transaction component for each query component.

Tak for hjælpen indtil videre ;)
Avatar billede martinlind Nybegynder
01. marts 2001 - 14:53 #8
flere Transaction\'s comp. er kun nødvendig vis du har flere instanser af dit datamodule og det har du kun hvis du kører multitier eller ISAPI, hvis det er en alm. app du laver så er det ikke nødvendigt med mere en en trans. comp.

/MArtin
Avatar billede retep Nybegynder
01. marts 2001 - 15:24 #9
Okay.

Men hvis jeg i programmets start sætter transaction.active := true får jeg en fejl når jeg laver en transaction.StartTransaction fra en anden form. (transaction is active)

Er der nogen grund til at sætte den aktiv i starten?
Avatar billede pellelil Nybegynder
01. marts 2001 - 15:26 #10
I InterBase foregår ALT i transaktioner og det SKAL foregå i transaktioner. Dette betydder således at når du COMMIT\'er din transaktion så lukkes de Datasets der benytter denne transaktion. Ligeledes når flere Datasets deler samme transaktion så har du ikke (på samme måde) kontrol over de enkelte transaktioner. Den Transaktion der således er på DataModulet er knyttet til min TDataBase (da den kræver en sådan) men på hver af mine forms knytter jeg en separat Transaktion til hver Dataset.

Dog kan jeg sagtens i forbindelse med en Master/Detail finde på at \"dele\" samme transaktion til flere Dataset da ændringer i såvels Master som Detail kan \"fortrydes\" med et kald til Rollback (eller RollbackRetaining)
Avatar billede retep Nybegynder
01. marts 2001 - 15:28 #11
Okay... Tak til jer igen ;)

Nu skal jeg nok oprette nye spørgsmål fremover!

Mvh
Retep
Avatar billede pellelil Nybegynder
01. marts 2001 - 15:29 #12
Hvis du gør som marinlind foreslår så er det nok at starte din (ene) transaktion når du starter dit program. Dog skal du være opmærksom på at du i dine forms SKAL kalde CommitRetaining og/eller RollBack retaining.

Hvis du i stedet gør som jeg foreslår (principielt en transaktion pr DataSet) så kan du groftsagt sige at den Transaktion der er på din DataBase ikke anvendes. På mine enkelte forms åbner jeg DataSet og starter transaktioner i formens OnCreate.

Smag og behag :-)
Avatar billede sannen Nybegynder
01. marts 2001 - 19:50 #13
jeg ved da godt hvorn du skal gøre..men det koster*GGG*
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester