尝试以下方法:
在您的程序 TfrmProfessions.Filter 的开头,添加这些行
Caption := dmPat.AdoTable1.FieldByName('Profession').ClassName; // the purpose of this is
// so that you can tell at a glance what field type your Professions field is. which could be important
Assert(Assigned(dmPat)); // Assert generates an exception if its argument is false
// so this checks that dmPat has been created
Assert(Assigned(dmPat.AdoTable1)); // checks that dmPat.AdoTable1 has been created.
Assert(dmPat.AdoTable1.Active); // checks that the table is open
这应该可以解决没有创建 db 对象的任何问题。
更新我从您的 cmets 得知您已经解决了您的异常
问题,并期待阅读您是如何做到的。同时,我一直
编写以下内容并决定发布它,因为它可能会给您和其他人一些见解
了解如何调查您报告的问题。
我在 D10.4.2 中启动了一个新的 VCL,并在主窗体中添加了一个 TAdoConnection、一个 TAdoTable、一个 TADoCommand、一个 TDataSource
连接到 AdoTable1,连接到 DataSource 的 TDBGrid 和 TDBNavigator 以及用于搜索文本的 TEdit,
加上几个 TButtons 来调用下面的例程。我没有打扰
将 TAdoTable 等放入 TDataModule 中,因为我已经提到了如何处理它。
然后我创建了一个测试 Access db,其中包含一个名为 AName 的文本字段和一个名为 ANumber 的数字字段,使用
以下代码
procedure TForm1.Button3Click(Sender: TObject);
begin
if AdoTable1.Active then
AdoTable1.Close;
AdoCommand1.CommandText :=
{.$define DropTable}
{$ifdef DropTable}
'Drop table MATest';
{$else}
'CREATE TABLE MATest (AName Char(12) , ANumber NUMBER)';
{$endif}
AdoCommand1.Execute;
end;
$ifdef 让我可以轻松放下桌子重新开始。
互联网上的“接受的智慧”
groups 似乎是要在 Delphi 代码中创建 Access 表,您需要使用 AdoX
ActiveX 库,它独立于 Ado 访问组件。然而,TAdoCommand 完全有能力做到这一点。
然后,我使用以下过程向其中添加了一些记录:
procedure TForm1.InsertData;
begin
ADoTable1.Open;
AdoTable1.InsertRecord(['aaa']);
AdoTable1.InsertRecord(['abb']);
AdoTable1.InsertRecord(['bbb']);
end;
请注意,这故意不为第二个字段 ANumber 指定值,因此在数据库文件中,ANumber
字段应该接收 Access 用于缺失值的任何值(我希望
为 Null,但无论如何。
顺便说一句,在调查问题时,我总是在代码中创建新记录,以便
值在程序的每次运行中都保持不变,这样我就不用思考要输入的数据了。
然后我为 AdoTable1 添加了这个 AfterScroll 事件
procedure TForm1.ADOTable1AfterScroll(DataSet: TDataSet);
var
F : TField;
S : String;
begin
F := AdoTable1.Fields[0];
S := F.AsString;
F := AdoTable1.Fields[1];
S := S + ' / ' + F.AsString;
Caption := S;
end;
这样做的目的是强制重新评估两者的字符串表示
字段以查看在表格中滚动是否引发了您遇到的异常。
结果:没有遇到异常。
然后我添加了以下代码来设置过滤
procedure TForm1.edtSearchChange(Sender: TObject);
begin
UpdateFilter;
end;
procedure TForm1.UpdateFilter;
begin
Assert(AdoTable1.Active); // checks that the table is open
AdoTable1.Filtered := False; // we should turn filtering off whether or not
// edSearchText.Text is blank or not
if Trim(edtSearch.Text) <> '' then begin // Trim() removes leading and trailing blanks
AdoTable1.Filter := 'AName LIKE ' + quotedstr('%' + edtSearch.Text + '%');
AdoTable1.Filtered := True;
end;
end;
而且效果很好。 aa 的过滤器匹配前两行,b 匹配第二行和第三行。 ADO Filter 属性记录在 here。
QED。我希望这个示例表明,通过逐步构建测试项目而不是尝试调试已完成的项目,可以更轻松地调查您遇到的问题。
调查这一切后,我注意到前段时间注意到的关于 ADO 的一些事情:Delphi TAdo 组件通过 Windows 中的 MDAC(Microsoft 数据访问组件)层访问数据库,并且在某些数据库操作失败后会产生异常MDAC 层,在重新启动 Windows 之前,该层的行为异常。我很确定我在这里遇到了这个问题,因为在我尝试成功过滤后,发生了一些错误或其他错误,之后我根本无法让 Ado 过滤工作(它总是产生空结果)直到 我重新启动了 Windows。之后,它又恢复正常工作了。
更新 2
有一个挥之不去的问题。为什么如果 TDBEdit 连接到我的
ANumber 字段(或您的 Hours 字段),它工作正常,但如果我们转移字段值
手动启动 TEdit 或 TSpinEdit,我们得到字符串转换异常?我明白了
用这段代码
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
sedNumber.Text := AdoTable1.FieldByName('ANumber').Value;
end;
答案在Vcl.DBCtrls单元的TDBedit源代码中找到:
procedure TDBEdit.DataChange(Sender: TObject);
begin
if FDataLink.Field <> nil then
begin
[...]
if FFocused and FDataLink.CanModify then
Text := FDataLink.Field.Text
else
begin
EditText := FDataLink.Field.DisplayText;
if FDataLink.Editing and FDataLink.FModified then
Modified := True;
end;
end [...]
请注意,这不会访问该字段的 Value,而是访问其 Text 或 DisplayText 属性
这就是答案。所以一个比你的更简洁的解决方法就是简单地做
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
sedNumber.Text := AdoTable1.FieldByName('ANumber').Text;
end;
这会在没有任何明确的 Null 检查的情况下使异常静音。它之所以有效是因为
procedure TFloatField.GetText
当字段包含 Null 时,在 Data.DB 中显式返回一个空字符串作为 Text 值。