我有以下代码;
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表单允许用户成功输入新记录(汽车),但尝试更新字段时也会出现以下错误 密钥列信息不足以更新或刷新“
我做错了什么???
答案 0 :(得分:2)
我的猜测是:
没有最近的更改
是因为数据尚未发布。而且不能从我所看到的。您尝试从两个表中插入和更新元组,但是您只获取了详细信息表的外键。想象一下,您希望更新此结果集(甚至可以通过某些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 列中获取了其唯一的外键,而您无法更新客户表:
UPDATE Customer SET Name = 'NewValue' WHERE <What?>
因为您没有获取任何唯一的主键。我想,同样的情况是发动机。我只是猜测,但我不相信已经为 WHERE 子句获取了任何元数据(这是唯一可以获得客户的唯一主键的地方表)。是的,您可以使用SQL命令工具作弊并使用为其他表提取的密钥,但是客户端引擎并不那么聪明,我必须添加。
您收到此错误:
用于更新或刷新的键列信息不足
因为ADO不知道哪个记录应更新(或刷新),因为两个表都缺少唯一标识符(您错过了获取的主要唯一键)。
我对可能解决方案的建议很简单,只需获取两个表的主要唯一键( CusCarID 是 CustomerCar 表的主要唯一键):
SELECT
Customer.CusID,
Customer.Name,
CustomerCar.CusCarID,
CustomerCar.Car
FROM
Customer, CustomerCar
WHERE
Customer.CusID = CustomerCar.CusID