如何在2个不同(但结构相同的)数据库表中编辑2行 - Delphi

时间:2016-10-03 18:59:08

标签: mysql sql database delphi

我在我的应用程序中使用了2个TDBGrid控件。

  • 第一个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字段(自动增量,主要,唯一,索引等)。我似乎无法绕过它。

我很新,所以请尽量提供完整的解释。

2 个答案:

答案 0 :(得分:2)

根据您显示的视频,唯一可能发生的方法是dbmodule.arhivaDataSetid.Value为1时dbmodule.comenziDataSetid.Value为3。在视频中清晰可见,在您编辑Orders DBGrid中的第三条记录之前,您在Archive中留下了第一个记录DBGrid选择而不是 3rd 记录。

假设两个表中的id值总是应该对于任何给定记录彼此匹配,那么在编辑{{1}时,您应该在两个SQL语句中使用dbmodule.comenziDataSetid.Value而不是dbmodule.arhivaDataSetid.Value DBGrid。同样,在编辑Orders表时,您应该在两个SQL语句中使用Archive。这样,您在两个语句中都使用了正确的ID。

或者,根本不要使用多个SQL语句。当在另一个表中插入/更新记录时,使用DB触发器自动在一个表中插入/更新记录。当数据库引擎可以在服务器端为您完成时,无需在代码中复制工作。

话虽如此,每个表的dbmodule.arhivaDataSetid.Value字段都是自动增量字段,这意味着只要将新记录插入该表,该表的值就会自动递增。因此,如果有时间将记录成功插入到一个表中但未能插入另一个表中,则很容易使您的ID不同步。因此,至少,您的2 id语句应该包含在数据库事务中,这样如果INSERT失败,您可以取消整个事务而不更改任何一个表(与您的{{1相同)语句)。此外,您应该考虑在两个INSERT字段上使用外键引用将它们链接在一起,这样如果有人删除了一个表中的记录,那么另一个表中的相应记录也将被删除。

就个人而言,我不会依赖于使用自动增量字段将两个表中的数据链接在一起。自动增量字段可用于识别各个表中的记录,但是当需要跨表链接数据时,最好使用更可靠和唯一的标识符,例如订单号,甚至是UUID。

另外,请注意您的代码受SQL注入攻击。你真的应该使用参数化查询而不是手动构建SQL语句。或者,至少使用UPDATE而不是手动在用户输入的文本周围添加引号。

答案 1 :(得分: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。