【问题标题】:DBgrid not showing changes and show error when to try update - Insufficient key column information for updating or refreshing [closed]DBgrid 在尝试更新时未显示更改并显示错误 - 用于更新或刷新的键列信息不足 [关闭]
【发布时间】:2018-01-10 21:56:44
【问题描述】:

我有以下代码;

    unit UNewCar;

    interface

    uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
    System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Vcl.StdCtrls, Vcl.Mask,
    Vcl.DBCtrls, Vcl.Grids, Vcl.DBGrids, Data.Win.ADODB, Datasnap.DBClient,
    Vcl.ExtCtrls;

    type
      TFNewCar = class(TForm)
      ADOConnection1: TADOConnection;
      ADOQueryTC: TADOQuery;
     DataSourceTC: TDataSource;
     ADOQueryCC: TADOQuery;
     DataSourceCC: TDataSource;

     DBLookupComboBox1: TDBLookupComboBox;
     Label1: TLabel;
     Label2: TLabel;
     BtnNew: TButton;
     BtnSave: TButton;
     DBGrid1: TDBGrid;
     ADOQueryTCCusID: TAutoIncField;
     ADOQueryTCName: TWideStringField;
     ADOQueryTCCName: TWideStringField;
     ADOQueryTCAdd: TWideMemoField;
     ADOQueryTCCity: TWideStringField;
     ADOQueryTCPhone: TWideStringField;
     ADOQueryTCEmail: TWideStringField;
     ADOQueryCCName: TWideStringField;
     ADOQueryCCCusID: TIntegerField;
     ADOQueryCCCar: TWideStringField;
     DBEdit1: TDBEdit;
     procedure BtnNewClick(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure btnSaveClick(Sender: TObject);
     procedure ADOQueryCCBeforeEdit(DataSet: TDataSet);
     procedure ADOQueryCCBeforeInsert(DataSet: TDataSet);
     procedure ADOQueryCCBeforePost(DataSet: TDataSet);
   private
    procedure CheckSaveButtonClicked;
    function GetSaveEnabled: Boolean;
    procedure SetSaveEnabled(const Value: Boolean);
  protected
   public
    SaveClicked : Boolean;
    property SaveEnabled : Boolean read GetSaveEnabled write SetSaveEnabled;
    end;

   var
    FNewCar: TFNewCar;

   implementation

   {$R *.dfm}

   procedure TFNewCar.FormCreate(Sender: TObject);
   begin
  SaveEnabled := False;
  ADOQueryCC.Open;
  ADOQueryTC.Open;
  ADOQueryCC.Requery;
end;

procedure TFNewCar.ADOQueryCCBeforeEdit(DataSet: TDataSet);
begin
  SaveEnabled := True;
end;

procedure TFNewCar.ADOQueryCCBeforeInsert(DataSet: TDataSet);
begin
  SaveEnabled := True;
  DBEdit1.SetFocus;
end;

procedure TFNewCar.ADOQueryCCBeforePost(DataSet: TDataSet);
begin
  CheckSaveButtonClicked;
end;

procedure TFNewCar.CheckSaveButtonClicked;
begin
  if not SaveClicked then begin
    AdoQueryCC.Cancel;
    Abort;   //  In case the user clicked the DBNavigator Save button
  end;
end;

procedure TFNewCar.btnSaveClick(Sender: TObject);
begin
  SaveClicked := True;
  if DBEdit1.Text = '' then
    begin
     ShowMessage('Please enter the missing data!');
    end
    else
    begin
    AdoQueryCC.Post;
    SaveEnabled := False;
    ADOQueryCC.close;
    ADOQueryCC.SQL.text:='SELECT tcustomer.Name,  tcustomercar.CusID,  tcustomercar.Car FROM tcustomer, tcustomercar WHERE tcustomer.CusID = tcustomercar.CusID';
    ADOQueryCC.Open;
    end;
end;

function TFNewCar.GetSaveEnabled: Boolean;
begin
  Result := btnSave.Enabled;
end;

procedure TFNewCar.SetSaveEnabled(const Value: Boolean);
begin
  btnSave.Enabled := Value;
  SaveClicked := False;
end;

procedure TFNewCar.BtnNewClick(Sender: TObject);
begin
ADOQueryCC.Insert;
end;

end.

遵循 AdoqueryCC =>SQL

SELECT tcustomer.Name,  tcustomercar.CusID,  tcustomercar.Car FROM tcustomer, tcustomercar WHERE tcustomer.CusID = tcustomercar.CusID

当我的表单 FNewCar 加载时它没有最近的更改,即使我尝试使用 Requery 并刷新来创建一个事件。 FNewCar 表单允许用户成功输入新记录(汽车),但是当尝试更新字段时也会出现以下错误“ 用于更新或刷新的键列信息不足"

我做错了什么???

ScreenShot

【问题讨论】:

  • 撇开最近的更改问题不谈,在代码的哪一行 exact 上,您会收到“Insufficient key column”错误?如果它不在你的q中,你需要添加发生错误的方法的代码。
  • 您缺少主键。
  • 你在问为什么你会被否决。这是因为您的 q 目前是题外话,因为您没有提供足够的信息让读者能够回答。 @Victoria 非常擅长回答问题,但即使是她也不得不猜测你在做什么。读者不必猜测。正如她所说,您应该提供 MCVE - 请参阅 stackoverflow.com/help/mcve
  • 所以,您不应该期望 SO 读者从外部来源下载材料 - 它可能被任何类型的恶意软件挖掘。您的 q 这里应该是独立的。查找并点击关于“如何提问”的 SO 链接。
  • 欢迎来到 Stack Overflow。 这是到其他地方的链接。请去那里,弄清楚我的问题是什么,然后回到这里给我一个解决方案不是这个网站的工作方式。 相关代码必须在您的问题本身中。请参阅 How to AskHow to Create a Minimal, Complete and Verifiable Example,然后回来并 edit 您的帖子提供最小代码,以便我们重现问题。如果你不能这样做,那么你的问题很可能不适合这个网站。

标签: delphi ms-access


【解决方案1】:

我的猜测是:

没有最近的变化

是因为数据还没有发布。并且不能从我所看到的。您正在尝试从两个表中插入和更新元组,但您只获取了一个明细表的外键。想象一下,您想更新这个结果集(甚至通过一些 SQL 命令工具手动更新):

SELECT
   Customer.Name,
   CustomerCar.CusID,
   CustomerCar.Car
FROM
   Customer, CustomerCar
WHERE
   Customer.CusID = CustomerCar.CusID

您可以更新 CustomerCar 表:

UPDATE CustomerCar SET Car = 'NewValue' WHERE CusID = <Fetched CustomerCar.CusID>

因为您在 CustomerCar.CusID 列中获取了它的唯一外键,而您无法更新 Customer 表:

UPDATE Customer SET Name = 'NewValue' WHERE <What?>

因为您没有获取任何唯一的主键。在同样的情况下是引擎,我猜。我只是猜测,但我认为没有为 WHERE 子句获取任何元数据(这是唯一可以获取 Customer 的唯一主键的地方> 表)。是的,您可以使用 SQL 命令工具作弊并使用为其他表获取的密钥,但客户端引擎并不那么聪明,我必须补充。

您收到此错误:

用于更新或刷新的键列信息不足

因为 ADO 不知道应该更新(或刷新)哪条记录,因为两个表都缺少唯一标识符(您错过了获取的主唯一键)。

我对可能解决方案的建议很简单,只需获取两个表的主唯一键(CusCarIDCustomerCar 表的主唯一键):

SELECT
   Customer.CusID,
   Customer.Name,
   CustomerCar.CusCarID,
   CustomerCar.Car
FROM
   Customer, CustomerCar
WHERE
   Customer.CusID = CustomerCar.CusID

【讨论】:

  • 我试图回答original question
  • 我将问题回滚到原来的状态。
  • @Victoria,我删除了我的评论,你得到了一个非常好的答案的支持。顺便说一句,ADO 能够处理连接查询的更新,只要您指定 ds.Properties['Update Criteria'] := adCriteriaKeyProperties['Unique Table'] := 'TheTable'(可能涉及更多我目前不记得的属性),并且它有一个更新的密钥。如果 OP 会在 MCVE 上做出努力,那它实际上也可能是一个非常好的问题
  • @Victoria 我刚接触编程真的很感谢你,现在它工作正常。现在在 SQL 中,我在第二个表(tcustomercar)中调用两个表 PK 和 FK 将 DBLookupComboBox=>DataField 更新为 tcustomercar.CusID 而不是 CusID。
  • @kobik,非常感谢!从未听说过这些(它们实际上是提示,说明无法从原始查询中获得)。菲亚兹,很高兴它有帮助。也许如果你尝试制作一个 MCVE,像 kobik 这样的其他人可能会给你更好的答案(我只是一个 FireDAC 人,而不是 ADO 专家:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-08
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多