2016-10-03 51 views
-1

我在我的應用程序中使用了2 TDBGrid控件。如何在2個不同(但相同結構)的數據庫表中編輯2行 - Delphi

  • 第1個DBGrid顯示來自名爲Orders的表中的數據。

  • 第二個DBGrid顯示來自名爲Archive的表中的數據。

兩個表是在同一數據庫中,並且具有相同的結構(相同數量和列的名稱,以及相同的設置)。

下面是兩個表的結構:

image

我用2個行動在我的應用程序:

  • 的第一個動作是Add Order。第二個動作是Edit Order

當我使用Add Order表單時,它成功添加了我在兩個表中的新行中輸入的詳細信息。

所以這個工程。

現在,我想選擇其中一行添加並編輯其信息。我使用Edit Order這個動作。它顯示了一個與要編輯和保存的信息類似的表單。它應該編輯兩個表中的信息。它的確如此,但ID改變了,我最終在第一個DBGrid上編輯了一些內容,而在第二個DBGrid中,它將信息更改爲其他內容(來自另一個ID)。

這裏是我的Edit動作代碼:

procedure TForm2.actEditComandaExecute(Sender: TObject); 
begin 
    if (dbmodule.SQLConnection1.Connected) and (dbmodule.comenziDataSet.IsEmpty = false) then 
    begin 
    editcustomerform.Edit1.Text := dbmodule.comenziDataSetstare.Value; 
    editcustomerform.Edit2.Text := dbmodule.comenziDataSetclient.Value; 
    editcustomerform.Edit3.Text := dbmodule.comenziDataSettelefon.Value; 
    editcustomerform.Edit4.Text := dbmodule.comenziDataSetemail.Value; 
    editcustomerform.Edit5.Text := dbmodule.comenziDataSetdetalii.Value; 
    editcustomerform.Edit6.Text := dbmodule.comenziDataSetpret.Value; 
    editcustomerform.Edit7.Text := dbmodule.comenziDataSetlivrare.Value; 
    editcustomerform.Edit8.Text := dbmodule.comenziDataSetuser.Value; 
    editcustomerform.Edit9.Text := dbmodule.comenziDataSetstatus.Value; 
    if editcustomerform.ShowModal = mrOk then 
    begin 
     dbmodule.SQLQuery1.SQL.Clear; 
     dbmodule.SQLQuery1.SQL.Add('UPDATE `tipotask`.`comenzi` SET `stare`=''' + editcustomerform.Edit1.Text + ''', `client`=''' + editcustomerform.Edit2.Text + ''', `telefon`=''' + editcustomerform.Edit3.Text + ''', `email`=''' + editcustomerform.Edit4.Text + ''', `detalii`=''' + editcustomerform.Edit5.Text + ''', `pret`=''' + editcustomerform.Edit6.Text + ''', `livrare`=''' + editcustomerform.Edit7.Text + ''', `user`=''' + editcustomerform.Edit8.Text + ''', `status`=''' + editcustomerform.Edit9.Text + ''' WHERE `id`=''' + IntToStr(dbmodule.comenziDataSetid.Value) + ''';'); 
     dbmodule.SQLQuery1.ExecSQL(true); 
     dbmodule.SQLQuery3.SQL.Clear; 
     dbmodule.SQLQuery3.SQL.Add('UPDATE `tipotask`.`arhiva` SET `stare`=''' + editcustomerform.Edit1.Text + ''', `client`=''' + editcustomerform.Edit2.Text + ''', `telefon`=''' + editcustomerform.Edit3.Text + ''', `email`=''' + editcustomerform.Edit4.Text + ''', `detalii`=''' + editcustomerform.Edit5.Text + ''', `pret`=''' + editcustomerform.Edit6.Text + ''', `livrare`=''' + editcustomerform.Edit7.Text + ''', `user`=''' + editcustomerform.Edit8.Text + ''', `status`=''' + editcustomerform.Edit9.Text + ''' WHERE `id`=''' + IntToStr(dbmodule.arhivaDataSetid.Value) + ''';'); 
     dbmodule.SQLQuery3.ExecSQL(true); 

     //we need to refresh the data 
     actRefreshData.Execute; 
    end; 
    end; 

這裏是發生了什麼事的視頻。請注意ID列如何改變和弄亂事情。

video removed - no need - solved

的最終目標是增加使用Add Order形式,效果很好,這增加的順序2表中的一個新的秩序。這很好。

每當我需要訂購Edit訂單,我只需在Orders DBGrid中選擇它並對其進行編輯。一旦我這樣做,它也應該更改Archive表中的相應信息 - 只是我正在編輯的記錄。

我該如何解決這個問題?

我已經在它上了幾個小時了,我無法弄清楚。我不理解ID字段(自動增量,主要,唯一,索引等)。我似乎無法把頭圍住它。

我很新,所以請儘量提供完整的解釋。

+0

您使用'AdoTable'? – Sami

+0

爲什麼在地球上使用數據控件(TDBGrid)來顯示數據,但是沒有數據庫感知的TEDits來編輯它?爲什麼不使用TDBEdits? – MartynA

+0

@Sami,他使用dbExpress(TSQLConnection而不是TADOConnection)。 –

回答

2

根據您展示的視頻,發生這種情況的唯一方法是​​爲3時dbmodule.arhivaDataSetid.Value爲1。它是在視頻清楚地看到,您編輯在Orders DBGrid中的記錄之前,你選擇,而不是記錄Archive的DBGrid離開記錄。

假設兩個表中的id值應始終相互匹配,對於任何給定的記錄,你應該在編輯Orders的DBGrid時將使用​​,而不是在這兩個SQL語句dbmodule.arhivaDataSetid.Value。同樣,在編輯Archive表時,您應該在兩個SQL語句中都使用dbmodule.arhivaDataSetid.Value。這樣,你在兩個語句中使用正確的ID。

或者,根本不要使用多個SQL語句。當在另一個表中插入/更新記錄時,可以使用數據庫觸發器自動在一個表中插入/更新記錄。當數據庫引擎可以在服務器端爲您完成時,無需在代碼中複製工作。

如此說來,每個表的id字段是自動遞增字段,這意味着該表的值被自動遞增,每當一個新的記錄被插入到該表。因此,如果有一段時間某個記錄成功插入到一張表中,但未能插入另一張表中,則很容易使您的ID不同步。所以,至少應該將您的2 INSERT語句包裝在數據庫事務中,以便如果任一INSERT失敗,則可以取消整個事務而不更改任何表(與您的UPDATE語句相同)。另外,您應該考慮在兩個id字段中使用外鍵引用將它們鏈接在一起,以便如果任何人刪除一個表中的記錄,則其他表中的對應記錄也會被刪除。

就我個人而言,我不會依賴於使用自動增量字段將兩個表中的數據鏈接在一起。自動遞增字段適用於識別單個表內的記錄,但是當數據需要跨表連接時,最好使用更可靠和唯一的標識符,例如訂單號,甚至UUID。

另外,請注意,您的代碼受SQL注入攻擊。您確實應該使用參數化查詢,而不是手動構建SQL語句。或者,至少使用QuotedStr()而不是手動在用戶輸入的文本週圍添加引號。

+0

嘿,那裏,謝謝你的內容豐富的帖子,它確實清理了一堆東西。我知道這是受SQL注入的影響,但它並不重要,因爲軟件將在我的辦公室被5個人的5人使用 - 沒有互聯網/沒有,他們也沒有任何關於sql和東西的線索。但是,是的,我認爲這是一個很好的習慣,學習正確的方法並避免它們在一起,我會期待偶然並使用參數。數據庫觸發器看起來如何,你提到的那個?這聽起來確實會讓事情變得更順暢,但我不知道如何使用/實現,再次感謝! – Petzy

+0

請參閱MySQL文檔中的[使用觸發器](http://dev.mysql.com/doc/refman/5.7/en/triggers.html)。 –

+0

會做,再次感謝! – Petzy

0

我相信你的問題是在這些表的更新:

dbmodule.SQLQuery1.SQL.Clear; 
    dbmodule.SQLQuery1.SQL.Add('UPDATE `tipotask`.`comenzi` SET .... WHERE `id`=''' + IntToStr(dbmodule.comenziDataSetid.Value) + ''';'); 
    dbmodule.SQLQuery1.ExecSQL(true); 
    dbmodule.SQLQuery3.SQL.Clear; 
    dbmodule.SQLQuery3.SQL.Add('UPDATE `tipotask`.`arhiva` SET .... WHERE `id`=''' + IntToStr(dbmodule.arhivaDataSetid.Value) + ''';'); 
    dbmodule.SQLQuery3.ExecSQL(true); 

正如你所說,問題是ID,但沒有因爲是自動增量,索引,...,而是因爲你正在使用相同的值更新兩個網格上的重點記錄,這通常是不同的記錄(兩個不同的ID)。

您應該有兩個不同的更新操作,並且取決於您是通過網格還是通過另一個網格進行編輯,您應該使用該網格上的ID進行更新。

第一個(當你在Comenzi的網格編輯):

dbmodule.SQLQuery1.SQL.Clear; 
    dbmodule.SQLQuery1.SQL.Add('UPDATE `tipotask`.`comenzi` SET .... WHERE `id`=''' + IntToStr(dbmodule.comenziDataSetid.Value) + ''';'); 
    dbmodule.SQLQuery1.ExecSQL(true); 
    dbmodule.SQLQuery3.SQL.Clear; 
    dbmodule.SQLQuery3.SQL.Add('UPDATE `tipotask`.`arhiva` SET .... WHERE `id`=''' + IntToStr(dbmodule.comenziDataSetid.Value) + ''';'); 
    dbmodule.SQLQuery3.ExecSQL(true); 

而第二個(當你在Archiva的網格編輯):

dbmodule.SQLQuery1.SQL.Clear; 
    dbmodule.SQLQuery1.SQL.Add('UPDATE `tipotask`.`comenzi` SET .... WHERE `id`=''' + IntToStr(dbmodule.arhivaDataSetid.Value) + ''';'); 
    dbmodule.SQLQuery1.ExecSQL(true); 
    dbmodule.SQLQuery3.SQL.Clear; 
    dbmodule.SQLQuery3.SQL.Add('UPDATE `tipotask`.`arhiva` SET .... WHERE `id`=''' + IntToStr(dbmodule.arhivaDataSetid.Value) + ''';'); 
    dbmodule.SQLQuery3.ExecSQL(true); 

一個更優雅的解決方案是有一個更新過程,並根據您正在編輯的網格傳遞dbmodule.arhivaDataSetid.Value或dbmodule.arhivaDataSetid.Value。

+0

嘿,確實你的答案有幫助。我不會在訂單上的Archive dbgrid上編輯,所以你的第二個代碼可以幫助你。它確實編輯了我正在瞄準的檔案中的相應條目,因爲它們是相同的ID並且始終是。非常感謝:) – Petzy

相關問題