我在我的应用程序中使用了2个TDBGrid
控件。
第一个DBGrid显示名为Orders
的表中的数据。
第二个DBGrid显示名为Archive
的表中的数据。
两个表都在同一个数据库中,并且具有相同的结构(相同的列数和名称,以及相同的设置)。
这两个表的结构如下:
我在我的应用程序中使用了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 :(得分: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。