首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用.mdb访问数据库筛选TAdoTable.Filter

如何使用.mdb访问数据库筛选TAdoTable.Filter
EN

Stack Overflow用户
提问于 2021-08-05 17:07:35
回答 2查看 479关注 0票数 1

我有一个带有TADOConnectionTADOTable,并且我想将包含或以用户键入的字符作为开头的职业的表筛选为表单上的TEdit。下面是我目前使用的代码:

代码语言:javascript
复制
procedure TfrmProfessions.Filter;
begin
  if edtSearch.text = '' then
  begin
    dmPAT.ADOTable1.filtered := false;
  end
  else
  begin
    with dmPAT.ADOTable1 do
    begin
      filtered := false;
      Filter := 'Profession LIKE ' + quotedstr(edtSearch.text + '%');
      filtered := true;
    end;
  end;
end;

我在这条线路上有一个访问权限冲突,我不知道如何解决它:

代码语言:javascript
复制
dmPAT.ADOTable1.filtered := false;

我怀疑这是因为,在表单的OnCreate事件中,我清除了TEdit,它在创建TADOTable对象之前调用了这个Filter procedure,但我不确定。

我遇到的另一个错误是Cannot convert type(Null) to type(String)。当我设置过滤器和它的过滤器时,我会得到这个结果,但是没有匹配过滤器的记录。我该怎么解决这个问题?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-08-05 20:59:01

尝试以下几点:

在过程TfrmProfessions.Filter的开头,添加以下行

代码语言:javascript
复制
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对象,那么就应该清除所有问题。

更新我从您的评论中收集到,您已经解决了异常问题,并期待阅读您是如何做到的。同时,我一直在写以下文章,并决定将其发布,因为它可能会让您和其他人对如何着手调查像您报告的问题有一些深入的了解。

我在D10.4.2中启动了一个新的VCL,并在主表单中添加了一个TAdoConnection、一个TAdoTable、一个TADoCommand、一个连接到AdoTable1的TDataSource、一个TDBGrid和连接到DataSource的TDBNavigator,以及一个搜索文本的TEdit,再加上几个TButtons来调用下面的例程。我没有费心把TAdoTable等放到一个TDataModule中,因为我已经提到了如何处理这个问题。

然后,我使用以下代码创建了一个带有名为AName的文本字段和第一个名为ANumber的测试访问数据库

代码语言:javascript
复制
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是为了让我能够轻松地放下桌子,重新开始。

互联网组中的“公认智慧”似乎是,要用Delphi代码创建一个访问表,您需要使用AdoX ActiveX库,它与Ado Access组件是分开的。然而,TAdoCommand完全能够做到这一点。

然后,我使用以下过程向它添加了一些记录:

代码语言:javascript
复制
procedure TForm1.InsertData;
begin
  ADoTable1.Open;

  AdoTable1.InsertRecord(['aaa']);
  AdoTable1.InsertRecord(['abb']);
  AdoTable1.InsertRecord(['bbb']);
end;

请注意,这并不是故意为第二个值ANumber字段指定值,因此在数据库文件中,ANumber字段应该接收对缺失值使用的任何值访问(我希望它是Null,但无论如何)。

顺便说一句,在调查问题时,我总是在代码中创建新的记录,这样在程序的每次运行中,这些值都保持不变,并将我想出的数据保存下来输入。

然后,我为AfterScroll添加了AdoTable1事件

代码语言:javascript
复制
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;

这样做的目的是迫使对两个字段的字符串表示进行重新评估,以查看表周围的滚动是否引发了您所得到的异常。结果:没有遇到例外情况。

然后,我添加了以下代码来设置筛选

代码语言:javascript
复制
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的过滤器匹配前两行rowa,b匹配第二行和第三行。ADO Filter属性是文档化的这里

QED。我希望这个例子表明,通过一步一步地构建一个测试项目,而不是试图调试一个已完成的项目,可以更容易地调查像您已经遇到的问题。

对所有这一切进行调查,我注意到了前面我注意到的一些事情: Delphi TAdo组件通过Windows中的MDAC ()层访问数据库,在某些数据库操作失败后,在MDAC层产生异常后,该层的行为就会异常,直到Windows重新启动。我很确定我在这里遇到了这种情况,因为在我成功地进行了过滤之后,出现了一些错误或其他错误,然后我就无法让Ado过滤工作(它总是产生空的结果),直到我重新启动Windows。在那之后,它又恢复了正常工作。

更新2

还有一个悬而未决的问题。为什么如果一个TDBEdit连接到我的ANumber字段(或您的小时1),那么它工作得很好,但是如果我们手动传输字段值inti TEdit或TSpinEdit,我们就会得到字符串转换异常?我用这个代码理解它

代码语言:javascript
复制
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  sedNumber.Text := AdoTable1.FieldByName('ANumber').Value;
end;

答案可以在TDBedit单元的Vcl.DBCtrls源代码中找到:

代码语言:javascript
复制
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,而是访问它的TextDisplayText属性,这就是答案。所以,一个比你的修正更简洁的方法就是简单地去做。

代码语言:javascript
复制
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  sedNumber.Text := AdoTable1.FieldByName('ANumber').Text;
end;

这可以在没有任何明确的空检查的情况下使异常保持沉默。它起作用是因为

代码语言:javascript
复制
procedure TFloatField.GetText

在Data.DB中,当字段包含空值时,显式返回空字符串作为Text值。

票数 1
EN

Stack Overflow用户

发布于 2021-08-07 07:41:52

所以我追踪了问题所在。在我的DataModule中的DataModule事件中,我调用了这个过程:

代码语言:javascript
复制
procedure TdmPAT.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  frmProfessions.Show_Record_Values;
end;

下面是带有DBGrid的表单中的过程

代码语言:javascript
复制
procedure TfrmProfessions.Show_Record_Values;
begin
  with dmPAT.ADOTable1 do
  begin
    sedPK.value := FieldByName('PK').value;
    sedHours.value := FieldByName('Hours').value;

    edtProfession.text := fields[1].value;
    edtCost.text := floattostrf(FieldByName('Cost').AsFloat, ffcurrency, 12, 2);

    if FieldByName('Popular').asboolean then
      rgpPopular.ItemIndex := 0
    else
      rgpPopular.ItemIndex := 1;
  end;
end;

现在,一旦我过滤了DBGrid,问题就出现了。这不是过滤器本身,但它会导致一个记录用空值显示。然后,当我试图在编辑中显示活动记录(null记录)时,delphi无法将Null转换为sedHours.value:=FieldByName('Hours').value;行中的字符串。

所以我才会犯错误。XD的一些尝试条款应该解决这个问题。我已经重新做了上述过程的代码,它解决了问题

代码语言:javascript
复制
procedure TfrmProfessions.Show_Record_Values;
var
  Profession, Hours, Cost, Popular: Tfield;
begin
  Profession := dmPAT.ADOTable1.fields[1];
  Hours := dmPAT.ADOTable1.fields[2];
  Cost := dmPAT.ADOTable1.fields[3];
  Popular := dmPAT.ADOTable1.fields[4];

  // check if null values
  if Profession.value = Null then
    edtProfession.text := ''
  else
    edtProfession.text := Profession.value;

  if Hours.value = Null then //The Hours Field is an Integer.
    sedHours.value := 0 //sedHours is a TSpinEdit.
  else
    sedHours.value := Hours.value;

  if Cost.value = Null then //The Cost field is Currency in MSAccess.
    edtCost.text := floattostrf(0, ffcurrency, 12, 2)
  else
    edtCost.text := floattostrf(Cost.value, ffcurrency, 12, 2);

  if Popular.value = Null then
  begin
    rgpPopular.ItemIndex := -1;
  end
  else
  begin
    case Popular.asboolean of
      true:
        rgpPopular.ItemIndex := 0;
      false:
        rgpPopular.ItemIndex := 1;
    end;
  end;
end;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68670837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档