多層資料庫開發十三:剖析幾個資料庫應用程式

來源:互聯網
上載者:User
第十三章 剖析幾個資料庫應用程式
  前面已經詳細講述了Delphi 4的資料庫編程技術。為了使讀者能夠透徹地理解有關編程技術並靈活運用,我們把Delphi 4的幾個示範程式拿出來加以剖析,這些示範程式都編得非常有技巧。要說明的是,剖析程式時我們可能會忽略掉一些與主題無關的細節。
13.1 一個後台查詢的示範程式
  這一節詳細剖析一個後台查詢的示範程式,項目名稱叫Bkquery,它可以在C:/Program Files/Borland/Delphi4/Demos/Db/Bkquery目錄中找到。它的主表單13.1所示。
  圖13.1 Bkquery的主表單
  我們先從處理表單的OnCreate事件的控制代碼開始,因為它是應用程式的起點。Procedure TAdhocForm. FormCreate(Sender: TObject);
Procedure CreateInitialIni;
  Const 
  VeryInefficientName = 'IB:
  Very Inefficient Query';
  VeryInefficientQuery ='select EMP_NO, Avg(Salary) as Salary/n'+' from employee, employee, employee/n' +'
 group by EMP_NO';
  AmountDueName = 'DB: Amount Due By Customer';
  AmountDueByCustomer ='select Company, Sum(ItemsTotal) - Sum(AmountPaid) as AmountDue/n' +'
  from customer, orders/n' +'
  where Customer.CustNo = Orders.CustNo/n' + ' group by Company';
  Begin
  With SavedQueries Do
   Begin
    WriteString(VeryInefficientName, 'Query', VeryInefficientQuery);
    WriteString(VeryInefficientName, 'Alias', 'IBLOCAL');
    WriteString(VeryInefficientName, 'Name', 'SYSDBA');
   SavedQueryCombo.Items.Add(VeryInefficientName);
   WriteString(AmountDueName, 'Query',  AmountDueByCustomer);
    WriteString(AmountDueName, 'Alias', 'DBDEMOS');
    WriteString(AmountDueName, 'Name', '');
    SavedQueryCombo.Items.Add(AmountDueName);
   End;
  End;
Begin
  Session.GetAliasNames(AliasCombo.Items);
  SavedQueries := TIniFile.Create('BKQUERY.INI');
  SavedQueries.ReadSections(SavedQueryCombo.Items);
  If SavedQueryCombo.Items.Count <= 0 then CreateInitialIni;
   SavedQueryCombo.ItemIndex := 0;
   QueryName := SavedQueryCombo.Items[0];
   Unmodify;ReadQuery;
End;
  FormCreate主要做了這麼幾件事情:首先,它調用TSession的GetAliasNames函數把所有已定義的BDE別名放到一個字串列表中,實際上就是填充圖13.1中的“Database Alias”框。接著,建立了一個TIniFile類型的對象執行個體,並指定檔案名稱是BKQUERY.INI。如果這個檔案現在還不存在的話,就需要調用CreateInitialIni去建立一個檔案。至於怎樣寫.INI檔案,這不是本章要討論的主題。最後,調用ReadQuery把檔案中儲存的有關參數讀出來。
  ReadQuery函數是這樣定義的:
Procedure TAdhocForm.ReadQuery;
Begin
If not CheckModified then Exit;
With SavedQueries Do
Begin
QueryName := SavedQueryCombo.Items[SavedQueryCombo.ItemIndex];
QueryEdit.Text := IniStrToStr(ReadString(QueryName, 'Query', ''));
AliasCombo.Text := ReadString(QueryName, 'Alias', '');
NameEdit.Text := ReadString(QueryName, 'Name', '');
End;
Unmodify;
If Showing thenIf NameEdit.Text <> '' then PasswordEdit.SetFocus else
QueryEdit.SetFocus;
End;
  當使用者單擊“Execute”按鈕,程式就調用BackgroundQuery在後台執行查詢。Procedure TAdhocForm.ExecuteBtnClick(Sender: TObject);
Begin
BackgroundQuery(QueryName, AliasCombo.Text, NameEdit.Text, PasswordEdit.Text,QueryEdit.Text);
BringToFront;
End;
  BackgroundQuery是在另一個叫ResItFrm的單元中定義的,後面將重點介紹這個過程。當使用者單擊“New”按鈕,程式就把表單上的一些視窗重新初始化。
Procedure TAdhocForm.NewBtnClick(Sender: TObject);
Function UniqueName: string;
var
I: Integer;
Begin
I := 1;
Repeat
Result := Format('Query%d', [I]);
Until
SavedQueryCombo.Items.IndexOf(Result) < 0;
End;
Begin
AliasCombo.Text := 'DBDEMOS';
NameEdit.Text := '';
PasswordEdit.Text := '';
QueryEdit.Text := '';QueryEdit.SetFocus;
QueryName := UniqueName;
SavedQueryCombo.ItemIndex := -1;
Unnamed := True;
End;
  當使用者單擊“Save”按鈕,程式就調用SaveQuery函數把當前有關參數儲存到.INI檔案中。
Procedure TAdhocForm.SaveBtnClick(Sender: TObject);
Begin
SaveQuery;
End;
  而SaveQuery是這樣定義的:
Procedure TAdhocForm.SaveQuery;
Begin
If Unnamed then SaveQueryAs
Else
With SavedQueries Do
Begin
WriteString(QueryName, 'Query', StrToIniStr(QueryEdit.Text));
WriteString(QueryName, 'Alias', AliasCombo.Text);
WriteString(QueryName, 'Name', NameEdit.Text);Unmodify;
End;
End;
  當使用者單擊“Save As”按鈕,程式調用SaveQueryAs函數以另一個名稱儲存有關參數。
Procedure TAdhocForm.SaveAsBtnClick(Sender: TObject);
Begin
SaveQueryAs;
End;
  而SaveQueryAs是這樣定義的:
Procedure TAdhocForm.SaveQueryAs;
Begin
If GetNewName(QueryName) then
Begin
Unnamed := False;
SaveQuery;
With SavedQueryCombo, Items Do
Begin
If IndexOf(QueryName) < 0 then Add(QueryName);
ItemIndex := IndexOf(QueryName);
End;
End;
End;
  其中,GetNewName是在一個叫SaveQAs的單元中定義的,它將開啟13.2所示的對話方塊,讓使用者輸入一個檔案名稱。圖13.2 指定另一個檔案名稱此外,程式還處理了SavedQueryCombo框的OnChange事件:
Procedure TAdhocForm.SavedQueryComboChange(Sender: TObject);
Begin
ReadQuery;
End;
  所謂後台查詢,實際上是運用多線程的編程技術,使查詢在一個專門的線程中進行。為此,首先要以TThread為基類聲明一個線程對象:
TypeTQueryThread = Class(TThread)PrivateQueryForm: TQueryForm;
MessageText: string;
Procedure ConnectQuery;
Procedure DisplayMessage;
ProtectedProcedure Execute;
override;
PublicConstructor Create(AQueryForm: TQueryForm);
End;
  我們先看線程對象是怎樣建立的:
Constructor TQueryThread.Create(AQueryForm: TQueryForm);
Begin
QueryForm := AQueryForm;
FreeOnTerminate := True;
Inherited Create(False);
End;
  當使用者單擊“Execute”按鈕,程式就調用BackgroundQuery函數在後台執行查詢。BackgroundQuery是這樣定義的:
Procedure BackgroundQuery(const QueryName, Alias, User, Password, QueryText: string);
var
QueryForm: TQueryForm;
Begin
QueryForm := TQueryForm.Create(Application);
With QueryForm, Database Do
Begin
Caption := QueryName;
QueryLabel.Caption := QueryText;
Show;
AliasName := Alias;
Params.Values['USER'] := User;
Params.Values['PASSWORD'] := Password;
Query.Sql.Text := QueryText;
End;
TQueryThread.Create(QueryForm);
End;
  BackgroundQuery主要做了三件事情,一是動態建立和顯示一個表單(TQueryForm),因為要用這個表單顯示查詢結果。二是把傳遞過來的參數分別賦給TDadabase構件的AliasName、Params以及TQuery構件的SQL屬性。三是建立線程對象的執行個體。由於線程對象的FreeOnTerminate屬性設為True,所以用不著專門去刪除線程對象。
  好,現在讓我們看看這個程式最關鍵的代碼,即線程對象的Execute函數:
Procedure TQueryThread.Execute;
varUniqueNumber: Integer;
Begin
Try
With QueryForm Do
Begin
UniqueNumber := GetUniqueNumber;
Session.SessionName := Format('%s%x', [Session.Name, UniqueNumber]);
Database.SessionName := Session.SessionName;
Database.DatabaseName:=Format('%s%x',[Database.Name,UniqueNumber]);
Query.SessionName := Database.SessionName;
Query.DatabaseName := Database.DatabaseName;
Query.Open;
Synchronize(ConnectQuery);MessageText := 'Query openned';
Synchronize(DisplayMessage);
End;
Except
On E: Exception Do
Begin
MessageText := Format('%s: %s.', [E.ClassName, E.Message]);
Synchronize(DisplayMessage);
End;
End;
End;
  由於這是個多線程的資料庫應用程式,因此,需要顯式地使用TSession構件,而且要保證每個線程所使用的BDE會話期對象是唯一的。所以,程式首先調用GetUniqueNumber來獲得一個唯一的序號。同樣,對於TDatabase構件來說,也有類似的問題。
  Execute通過Synchronize讓主線程去執行ConnectQuery、DisplayMessage等方法,這是因為ConnectQuery、DisplayMessage都需要與VCL打交道,必須用Synchronize作外套。
13.2 一個緩衝更新的示範程式
  這一節詳細剖析一個緩衝更新的示範程式,項目名稱叫Cache,它可以在C:/Program Files/Borland/Delphi4/Demos/Db/Cacheup目錄中找到。它的主表單13.3所示。
  圖13.3 Cache的主表單
  主表單上有一個“Cached Updates”複選框,如果選中此複選框,表示使用緩衝更新技術。否則,表示不使用緩衝更新技術,當使用者修改了資料後,資料被直接寫到資料集中。
  主表單上還有一個“Use Update SQL”複選框,如果選中這個複選框,表示使用TUpdateSQL構件來進行緩衝更新。
  當使用者單擊“Apply Updates”按鈕,就向資料庫申請更新資料。
  當使用者單擊“Cancel Updates”按鈕,所有未決的修改將被取消。
  當使用者單擊“Revert Record”按鈕,對目前記錄所作的修改將被取消。
  在“Show Records”群組方塊內有幾個複選框,用於選擇要在柵格中顯示哪些記錄,包括未修改的記錄、修改的記錄、插入的記錄和刪除的記錄。
  當使用者單擊“Re-Execute Query”按鈕,就重新執行查詢。此外,這個示範程式還用一個計算欄位來表達當前的更新狀態。
  下面我們就來看看怎樣實現上述功能。在介紹程式碼之前,我們先要介紹資料模組CacheData,因為幾個關鍵的構件都是放在這個資料模組上,13.4所示。
  圖13.4 資料模組
  資料模組上有四個構件,分別是:一個TDataSource構件,其名為CacheDS,一個TDatabase構件名為CacheDB,一個TQuery構件名為CacheQuery,一個TUpdateSQL構件名為UpdateSQL。
  TQuery構件的OnCalcFields事件是這樣處理的:
Procedure TCacheData.CacheQueryCalcFields(DataSet: TDataSet);
ConstUpdateStatusStr: array[TUpdateStatus] of string = ('Unmodified', 'Modified','Inserted', 'Deleted');
Begin
If CacheQuery.CachedUpdates then
  CacheQueryUpdateStatus.Value := UpdateStatusStr[CacheQuery.UpdateStatus];
End;
  上述代碼用於給計算欄位CacheQueryUpdateStatus賦值,以顯示當前的更新狀態。TQuery構件的OnUpdateError事件是這樣處理的:
Procedure TCacheData.UpdateErrorHandler(DataSet: TDataSet; E: EDatabaseError;
UpdateKind:TUpdateKind;
var UpdateAction: TUpdateAction);
Begin
UpdateAction := UpdateErrorForm.HandleError(DataSet, E, UpdateKind);
End;
  現在我們回到主表單,從處理主表單的OnCreate事件的控制代碼開始。
Procedure TCacheDemoForm. FormCreate(Sender: TObject);
Begin
FDataSet := CacheData.CacheDS.DataSet as TDBDataSet;
FDataSet.CachedUpdates := CachedUpdates.Checked;
SetControlStates(FDataSet.CachedUpdates);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.